mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-05-08 16:05:05 -04:00
Merge f05fc7ba31
into 7232dff6db
This commit is contained in:
commit
f60a9cce17
27 changed files with 1353 additions and 1344 deletions
134
node/db/API.js
134
node/db/API.js
|
@ -29,7 +29,7 @@ var sessionManager = require("./SessionManager");
|
|||
var async = require("async");
|
||||
var exportHtml = require("../utils/ExportHtml");
|
||||
var importHtml = require("../utils/ImportHtml");
|
||||
var cleanText = require("./Pad").cleanText;
|
||||
var cleanText = require("../utils/cleantext").cleanText;
|
||||
|
||||
/**********************/
|
||||
/**GROUP FUNCTIONS*****/
|
||||
|
@ -63,7 +63,7 @@ exports.listSessionsOfAuthor = sessionManager.listSessionsOfAuthor;
|
|||
/************************/
|
||||
|
||||
/**
|
||||
getText(padID, [rev]) returns the text of a pad
|
||||
getText(padID, [rev]) returns the text of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -78,14 +78,14 @@ exports.getText = function(padID, rev, callback)
|
|||
callback = rev;
|
||||
rev = undefined;
|
||||
}
|
||||
|
||||
|
||||
//check if rev is a number
|
||||
if(rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(rev)))
|
||||
if(!isNaN(parseInt(rev, 10)))
|
||||
{
|
||||
rev = parseInt(rev);
|
||||
rev = parseInt(rev, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -93,26 +93,26 @@ exports.getText = function(padID, rev, callback)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(rev !== undefined && rev < 0)
|
||||
{
|
||||
callback(new customError("rev is a negativ number","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//ensure this is not a float value
|
||||
if(rev !== undefined && !is_int(rev))
|
||||
{
|
||||
callback(new customError("rev is a float value","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
|
@ -122,16 +122,16 @@ exports.getText = function(padID, rev, callback)
|
|||
callback(new customError("rev is higher than the head revision of the pad","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//get the text of this revision
|
||||
pad.getInternalRevisionAText(rev, function(err, atext)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
data = {text: atext.text};
|
||||
|
||||
|
||||
callback(null, data);
|
||||
})
|
||||
});
|
||||
}
|
||||
//the client wants the latest text, lets return it to him
|
||||
else
|
||||
|
@ -139,10 +139,10 @@ exports.getText = function(padID, rev, callback)
|
|||
callback(null, {"text": pad.text()});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setText(padID, text) sets the text of a pad
|
||||
setText(padID, text) sets the text of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -151,22 +151,22 @@ Example returns:
|
|||
{code: 1, message:"text too long", data: null}
|
||||
*/
|
||||
exports.setText = function(padID, text, callback)
|
||||
{
|
||||
{
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//set the text
|
||||
pad.setText(text);
|
||||
|
||||
|
||||
//update the clients on the pad
|
||||
padMessageHandler.updatePadClients(pad, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getHTML(padID, [rev]) returns the html of a pad
|
||||
getHTML(padID, [rev]) returns the html of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -178,14 +178,14 @@ exports.getHTML = function(padID, rev, callback)
|
|||
if(typeof rev == "function")
|
||||
{
|
||||
callback = rev;
|
||||
rev = undefined;
|
||||
rev = undefined;
|
||||
}
|
||||
|
||||
if (rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (!isNaN(parseInt(rev)))
|
||||
if (!isNaN(parseInt(rev, 10)))
|
||||
{
|
||||
rev = parseInt(rev);
|
||||
rev = parseInt(rev, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ exports.getHTML = function(padID, rev, callback)
|
|||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
|
@ -219,8 +219,8 @@ exports.getHTML = function(padID, rev, callback)
|
|||
callback(new customError("rev is higher than the head revision of the pad","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
//get the html of this revision
|
||||
|
||||
//get the html of this revision
|
||||
exportHtml.getPadHTML(pad, rev, function(err, html)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
@ -234,14 +234,14 @@ exports.getHTML = function(padID, rev, callback)
|
|||
exportHtml.getPadHTML(pad, undefined, function (err, html)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
data = {html: html};
|
||||
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.setHTML = function(padID, html, callback)
|
||||
{
|
||||
|
@ -257,14 +257,14 @@ exports.setHTML = function(padID, html, callback)
|
|||
padMessageHandler.updatePadClients(pad, callback);
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*****************/
|
||||
/**PAD FUNCTIONS */
|
||||
/*****************/
|
||||
|
||||
/**
|
||||
getRevisionsCount(padID) returns the number of revisions of this pad
|
||||
getRevisionsCount(padID) returns the number of revisions of this pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -277,13 +277,13 @@ exports.getRevisionsCount = function(padID, callback)
|
|||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
callback(null, {revisions: pad.getHeadRevisionNumber()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
createPad(padName [, text]) creates a new pad in this group
|
||||
createPad(padName [, text]) creates a new pad in this group
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -291,24 +291,24 @@ Example returns:
|
|||
{code: 1, message:"pad does already exist", data: null}
|
||||
*/
|
||||
exports.createPad = function(padID, text, callback)
|
||||
{
|
||||
{
|
||||
//ensure there is no $ in the padID
|
||||
if(padID && padID.indexOf("$") != -1)
|
||||
{
|
||||
callback(new customError("createPad can't create group pads","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//create pad
|
||||
getPadSafe(padID, false, text, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
deletePad(padID) deletes a pad
|
||||
deletePad(padID) deletes a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -320,13 +320,13 @@ exports.deletePad = function(padID, callback)
|
|||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
pad.remove(callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getReadOnlyLink(padID) returns the read only link of a pad
|
||||
getReadOnlyLink(padID) returns the read only link of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -339,7 +339,7 @@ exports.getReadOnlyID = function(padID, callback)
|
|||
getPadSafe(padID, true, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//get the readonlyId
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readOnlyId)
|
||||
{
|
||||
|
@ -347,10 +347,10 @@ exports.getReadOnlyID = function(padID, callback)
|
|||
callback(null, {readOnlyID: readOnlyId});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setPublicStatus(padID, publicStatus) sets a boolean for the public status of a pad
|
||||
setPublicStatus(padID, publicStatus) sets a boolean for the public status of a pad
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -370,20 +370,20 @@ exports.setPublicStatus = function(padID, publicStatus, callback)
|
|||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//convert string to boolean
|
||||
if(typeof publicStatus == "string")
|
||||
publicStatus = publicStatus == "true" ? true : false;
|
||||
|
||||
|
||||
//set the password
|
||||
pad.setPublicStatus(publicStatus);
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getPublicStatus(padID) return true of false
|
||||
getPublicStatus(padID) return true of false
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -398,18 +398,18 @@ exports.getPublicStatus = function(padID, callback)
|
|||
callback(new customError("You can only get/set the publicStatus of pads that belong to a group","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
callback(null, {publicStatus: pad.getPublicStatus()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setPassword(padID, password) returns ok or a error message
|
||||
setPassword(padID, password) returns ok or a error message
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -424,21 +424,21 @@ exports.setPassword = function(padID, password, callback)
|
|||
callback(new customError("You can only get/set the password of pads that belong to a group","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//set the password
|
||||
pad.setPassword(password);
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
isPasswordProtected(padID) returns true or false
|
||||
isPasswordProtected(padID) returns true or false
|
||||
|
||||
Example returns:
|
||||
|
||||
|
@ -458,10 +458,10 @@ exports.isPasswordProtected = function(padID, callback)
|
|||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
callback(null, {isPasswordProtected: pad.isPasswordProtected()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/******************************/
|
||||
/** INTERNAL HELPER FUNCTIONS */
|
||||
|
@ -469,8 +469,8 @@ exports.isPasswordProtected = function(padID, callback)
|
|||
|
||||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
|
||||
}
|
||||
|
||||
//gets a pad safe
|
||||
|
@ -488,26 +488,26 @@ function getPadSafe(padID, shouldExist, text, callback)
|
|||
callback(new customError("padID is not a string","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//check if the padID maches the requirements
|
||||
if(!padManager.isValidPadId(padID))
|
||||
{
|
||||
callback(new customError("padID did not match requirements","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//check if the pad exists
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//does not exist, but should
|
||||
if(exists == false && shouldExist == true)
|
||||
if(!exists && shouldExist)
|
||||
{
|
||||
callback(new customError("padID does not exist","apierror"));
|
||||
}
|
||||
//does exists, but shouldn't
|
||||
else if(exists == true && shouldExist == false)
|
||||
else if(exists && !shouldExist)
|
||||
{
|
||||
callback(new customError("padID does already exist","apierror"));
|
||||
}
|
||||
|
|
|
@ -31,14 +31,14 @@ exports.doesAuthorExists = function (authorID, callback)
|
|||
db.get("globalAuthor:" + authorID, function (err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, author != null);
|
||||
callback(null, author ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a token.
|
||||
* @param {String} token The token
|
||||
* @param {Function} callback callback (err, author)
|
||||
* Returns the AuthorID for a token.
|
||||
* @param {String} token The token
|
||||
* @param {Function} callback callback (err, author)
|
||||
*/
|
||||
exports.getAuthor4Token = function (token, callback)
|
||||
{
|
||||
|
@ -48,52 +48,54 @@ exports.getAuthor4Token = function (token, callback)
|
|||
//return only the sub value authorID
|
||||
callback(null, author ? author.authorID : author);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a mapper.
|
||||
* Returns the AuthorID for a mapper.
|
||||
* @param {String} token The mapper
|
||||
* @param {Function} callback callback (err, author)
|
||||
* @param {Function} callback callback (err, author)
|
||||
*/
|
||||
exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
||||
{
|
||||
mapAuthorWithDBKey("mapper2author", authorMapper, function(err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//set the name of this author
|
||||
if(name)
|
||||
{
|
||||
exports.setAuthorName(author.authorID, name);
|
||||
|
||||
}
|
||||
|
||||
//return the authorID
|
||||
callback(null, author);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a mapper. We can map using a mapperkey,
|
||||
* so far this is token2author and mapper2author
|
||||
* @param {String} mapperkey The database key name for this mapper
|
||||
* @param {String} mapperkey The database key name for this mapper
|
||||
* @param {String} mapper The mapper
|
||||
* @param {Function} callback callback (err, author)
|
||||
* @param {Function} callback callback (err, author)
|
||||
*/
|
||||
function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
||||
{
|
||||
{
|
||||
//try to map to an author
|
||||
db.get(mapperkey + ":" + mapper, function (err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//there is no author with this mapper, so create one
|
||||
if(author == null)
|
||||
if(!author)
|
||||
{
|
||||
exports.createAuthor(null, function(err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//create the token2author relation
|
||||
db.set(mapperkey + ":" + mapper, author.authorID);
|
||||
|
||||
|
||||
//return the author
|
||||
callback(null, author);
|
||||
});
|
||||
|
@ -103,7 +105,7 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
|||
{
|
||||
//update the timestamp of this author
|
||||
db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime());
|
||||
|
||||
|
||||
//return the author
|
||||
callback(null, {authorID: author});
|
||||
}
|
||||
|
@ -111,22 +113,22 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
|||
}
|
||||
|
||||
/**
|
||||
* Internal function that creates the database entry for an author
|
||||
* @param {String} name The name of the author
|
||||
* Internal function that creates the database entry for an author
|
||||
* @param {String} name The name of the author
|
||||
*/
|
||||
exports.createAuthor = function(name, callback)
|
||||
{
|
||||
//create the new author name
|
||||
var author = "a." + randomString(16);
|
||||
|
||||
|
||||
//create the globalAuthors db entry
|
||||
var authorObj = {"colorId" : Math.floor(Math.random()*32), "name": name, "timestamp": new Date().getTime()};
|
||||
|
||||
|
||||
//set the global author db entry
|
||||
db.set("globalAuthor:" + author, authorObj);
|
||||
|
||||
|
||||
callback(null, {authorID: author});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the Author Obj of the author
|
||||
|
@ -136,7 +138,7 @@ exports.createAuthor = function(name, callback)
|
|||
exports.getAuthor = function (author, callback)
|
||||
{
|
||||
db.get("globalAuthor:" + author, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the color Id of the author
|
||||
|
@ -146,7 +148,7 @@ exports.getAuthor = function (author, callback)
|
|||
exports.getAuthorColorId = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the color Id of the author
|
||||
|
@ -156,7 +158,7 @@ exports.getAuthorColorId = function (author, callback)
|
|||
exports.setAuthorColorId = function (author, colorId, callback)
|
||||
{
|
||||
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the author
|
||||
|
@ -166,7 +168,7 @@ exports.setAuthorColorId = function (author, colorId, callback)
|
|||
exports.getAuthorName = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["name"], callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the name of the author
|
||||
|
@ -176,12 +178,12 @@ exports.getAuthorName = function (author, callback)
|
|||
exports.setAuthorName = function (author, name, callback)
|
||||
{
|
||||
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
*/
|
||||
function randomString(len)
|
||||
function randomString(len)
|
||||
{
|
||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
var randomstring = '';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* The DB Module provides a database initalized with the settings
|
||||
* The DB Module provides a database initalized with the settings
|
||||
* provided by the settings module
|
||||
*/
|
||||
|
||||
|
@ -33,14 +33,14 @@ exports.db = null;
|
|||
|
||||
/**
|
||||
* Initalizes the database with the settings provided by the settings module
|
||||
* @param {Function} callback
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.init = function(callback)
|
||||
{
|
||||
//initalize the database async
|
||||
db.init(function(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");
|
||||
|
@ -50,8 +50,8 @@ exports.init = function(callback)
|
|||
//everything ok
|
||||
else
|
||||
{
|
||||
exports.db = db;
|
||||
exports.db = db;
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,29 +17,29 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
|
||||
|
||||
exports.deleteGroup = function(groupID, callback)
|
||||
{
|
||||
var group;
|
||||
|
||||
async.series([
|
||||
//ensure group exists
|
||||
//ensure group exists
|
||||
function (callback)
|
||||
{
|
||||
//try to get the group entry
|
||||
db.get("group:" + groupID, function (err, _group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(_group == null)
|
||||
if(!_group)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -60,14 +60,14 @@ exports.deleteGroup = function(groupID, callback)
|
|||
{
|
||||
padIDs.push(i);
|
||||
}
|
||||
|
||||
//loop trough all pads and delete them
|
||||
|
||||
//loop trough all pads and delete them
|
||||
async.forEach(padIDs, function(padID, callback)
|
||||
{
|
||||
padManager.getPad(padID, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
pad.remove(callback);
|
||||
});
|
||||
}, callback);
|
||||
|
@ -79,18 +79,21 @@ exports.deleteGroup = function(groupID, callback)
|
|||
db.get("group2sessions:" + groupID, function (err, group2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//skip if there is no group2sessions entry
|
||||
if(group2sessions == null) {callback(); return}
|
||||
|
||||
if(!group2sessions) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//collect all sessions in an array, that allows us to use async.forEach
|
||||
var sessions = [];
|
||||
for(var i in group2sessions.sessionsIDs)
|
||||
{
|
||||
sessions.push(i);
|
||||
}
|
||||
|
||||
//loop trough all sessions and delete them
|
||||
|
||||
//loop trough all sessions and delete them
|
||||
async.forEach(sessions, function(session, callback)
|
||||
{
|
||||
sessionManager.deleteSession(session, callback);
|
||||
|
@ -109,27 +112,27 @@ exports.deleteGroup = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.doesGroupExist = function(groupID, callback)
|
||||
{
|
||||
//try to get the group entry
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, group != null);
|
||||
callback(null, group ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroup = function(callback)
|
||||
{
|
||||
//search for non existing groupID
|
||||
var groupID = "g." + randomString(16);
|
||||
|
||||
|
||||
//create the group
|
||||
db.set("group:" + groupID, {pads: {}});
|
||||
callback(null, {groupID: groupID});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
||||
{
|
||||
|
@ -139,22 +142,22 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
|||
callback(new customError("groupMapper is no string","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//try to get a group for this mapper
|
||||
db.get("mapper2group:"+groupMapper, function(err, groupID)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//there is no group for this mapper, let's create a group
|
||||
if(groupID == null)
|
||||
if(!groupID)
|
||||
{
|
||||
exports.createGroup(function(err, responseObj)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//create the mapper entry for this group
|
||||
db.set("mapper2group:"+groupMapper, responseObj.groupID);
|
||||
|
||||
|
||||
callback(null, responseObj);
|
||||
});
|
||||
}
|
||||
|
@ -165,7 +168,7 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
|||
callback(null, {groupID: groupID});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroupPad = function(groupID, padName, text, callback)
|
||||
{
|
||||
|
@ -173,15 +176,15 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
var padID = groupID + "$" + padName;
|
||||
|
||||
async.series([
|
||||
//ensure group exists
|
||||
//ensure group exists
|
||||
function (callback)
|
||||
{
|
||||
exports.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -198,9 +201,9 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//pad exists already
|
||||
if(exists == true)
|
||||
if(exists)
|
||||
{
|
||||
callback(new customError("padName does already exist","apierror"));
|
||||
}
|
||||
|
@ -231,16 +234,16 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback(null, {padID: padID});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.listPads = function(groupID, callback)
|
||||
{
|
||||
exports.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -254,12 +257,12 @@ exports.listPads = function(groupID, callback)
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
*/
|
||||
function randomString(len)
|
||||
function randomString(len)
|
||||
{
|
||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
var randomstring = '';
|
||||
|
|
896
node/db/Pad.js
896
node/db/Pad.js
|
@ -2,8 +2,6 @@
|
|||
* The pad object, defined with joose
|
||||
*/
|
||||
|
||||
require('joose');
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var Changeset = require("../utils/Changeset");
|
||||
var AttributePoolFactory = require("../utils/AttributePoolFactory");
|
||||
|
@ -15,497 +13,463 @@ var padManager = require("./PadManager");
|
|||
var padMessageHandler = require("../handler/PadMessageHandler");
|
||||
var readOnlyManager = require("./ReadOnlyManager");
|
||||
var crypto = require("crypto");
|
||||
var cleanText = require("../utils/cleantext").cleanText;
|
||||
|
||||
/**
|
||||
* Copied from the Etherpad source code. It converts Windows line breaks to Unix line breaks and convert Tabs to spaces
|
||||
* @param txt
|
||||
*/
|
||||
exports.cleanText = function (txt) {
|
||||
return txt.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
|
||||
}
|
||||
var Pad = function Pad(id) {
|
||||
this.atext = Changeset.makeAText("\n");
|
||||
this.pool = AttributePoolFactory.createAttributePool();
|
||||
this.head = -1;
|
||||
this.chatHead = -1;
|
||||
this.publicStatus = false;
|
||||
this.passwordHash = null;
|
||||
this.id = id;
|
||||
};
|
||||
|
||||
Class('Pad', {
|
||||
exports.Pad = Pad;
|
||||
|
||||
// these are the properties
|
||||
has : {
|
||||
|
||||
atext : {
|
||||
is : 'rw', // readwrite
|
||||
init : function() { return Changeset.makeAText("\n"); } // first value
|
||||
}, // atext
|
||||
|
||||
pool : {
|
||||
is: 'rw',
|
||||
init : function() { return AttributePoolFactory.createAttributePool(); },
|
||||
getterName : 'apool' // legacy
|
||||
}, // pool
|
||||
|
||||
head : {
|
||||
is : 'rw',
|
||||
init : -1,
|
||||
getterName : 'getHeadRevisionNumber'
|
||||
}, // head
|
||||
|
||||
chatHead : {
|
||||
is: 'rw',
|
||||
init: -1
|
||||
}, // chatHead
|
||||
|
||||
publicStatus : {
|
||||
is: 'rw',
|
||||
init: false,
|
||||
getterName : 'getPublicStatus'
|
||||
}, //publicStatus
|
||||
|
||||
passwordHash : {
|
||||
is: 'rw',
|
||||
init: null
|
||||
}, // passwordHash
|
||||
|
||||
id : { is : 'r' }
|
||||
},
|
||||
Pad.prototype.apool = function apool() {
|
||||
return this.pool;
|
||||
};
|
||||
|
||||
methods : {
|
||||
|
||||
BUILD : function (id)
|
||||
Pad.prototype.getHeadRevisionNumber = function getHeadRevisionNumber() {
|
||||
return this.head;
|
||||
};
|
||||
|
||||
Pad.prototype.getPublicStatus = function getPublicStatus() {
|
||||
return this.publicStatus;
|
||||
};
|
||||
|
||||
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||
|
||||
if(!author)
|
||||
{
|
||||
author = '';
|
||||
}
|
||||
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
||||
var newRev = ++this.head;
|
||||
|
||||
var newRevData = {};
|
||||
newRevData.changeset = aChangeset;
|
||||
newRevData.meta = {};
|
||||
newRevData.meta.author = author;
|
||||
newRevData.meta.timestamp = new Date().getTime();
|
||||
|
||||
//ex. getNumForAuthor
|
||||
if(author !== '')
|
||||
{
|
||||
this.pool.putAttrib(['author', author || '']);
|
||||
}
|
||||
|
||||
if(newRev % 100 === 0)
|
||||
{
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||
db.set("pad:"+this.id, {atext: this.atext,
|
||||
pool: this.pool.toJsonable(),
|
||||
head: this.head,
|
||||
chatHead: this.chatHead,
|
||||
publicStatus: this.publicStatus,
|
||||
passwordHash: this.passwordHash});
|
||||
|
||||
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||
var authors = [];
|
||||
|
||||
for(var key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] !== "")
|
||||
{
|
||||
return {
|
||||
'id' : id,
|
||||
}
|
||||
},
|
||||
|
||||
appendRevision : function(aChangeset, author)
|
||||
{
|
||||
if(!author)
|
||||
author = '';
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
}
|
||||
}
|
||||
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
||||
var newRev = ++this.head;
|
||||
|
||||
var newRevData = {};
|
||||
newRevData.changeset = aChangeset;
|
||||
newRevData.meta = {};
|
||||
newRevData.meta.author = author;
|
||||
newRevData.meta.timestamp = new Date().getTime();
|
||||
|
||||
//ex. getNumForAuthor
|
||||
if(author != '')
|
||||
this.pool.putAttrib(['author', author || '']);
|
||||
|
||||
if(newRev % 100 == 0)
|
||||
{
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||
db.set("pad:"+this.id, {atext: this.atext,
|
||||
pool: this.pool.toJsonable(),
|
||||
head: this.head,
|
||||
chatHead: this.chatHead,
|
||||
publicStatus: this.publicStatus,
|
||||
passwordHash: this.passwordHash});
|
||||
}, //appendRevision
|
||||
|
||||
getRevisionChangeset : function(revNum, callback)
|
||||
return authors;
|
||||
};
|
||||
|
||||
Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targetRev, callback) {
|
||||
var _this = this;
|
||||
|
||||
var keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
var atext;
|
||||
var changesets = [];
|
||||
|
||||
//find out which changesets are needed
|
||||
var neededChangesets = [];
|
||||
var curRev = keyRev;
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
neededChangesets.push(curRev);
|
||||
}
|
||||
|
||||
async.series([
|
||||
//get all needed data out of the database
|
||||
function(callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
||||
}, // getRevisionChangeset
|
||||
|
||||
getRevisionAuthor : function(revNum, callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
|
||||
}, // getRevisionAuthor
|
||||
|
||||
getRevisionDate : function(revNum, callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
||||
}, // getRevisionAuthor
|
||||
|
||||
getAllAuthors : function()
|
||||
{
|
||||
var authors = [];
|
||||
|
||||
for(key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "")
|
||||
async.parallel([
|
||||
//get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
changesets[item] = changeset;
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
}
|
||||
|
||||
return authors;
|
||||
], callback);
|
||||
},
|
||||
|
||||
getInternalRevisionAText : function(targetRev, callback)
|
||||
//apply all changesets to the key changeset
|
||||
function(callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
||||
var keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
var atext;
|
||||
var changesets = [];
|
||||
|
||||
//find out which changesets are needed
|
||||
var neededChangesets = [];
|
||||
var apool = _this.apool();
|
||||
var curRev = keyRev;
|
||||
while (curRev < targetRev)
|
||||
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
neededChangesets.push(curRev);
|
||||
var cs = changesets[curRev];
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
|
||||
async.series([
|
||||
//get all needed data out of the database
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
changesets[item] = changeset;
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//apply all changesets to the key changeset
|
||||
function(callback)
|
||||
{
|
||||
var apool = _this.apool();
|
||||
var curRev = keyRev;
|
||||
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
var cs = changesets[curRev];
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
|
||||
callback(null);
|
||||
}
|
||||
], function(err)
|
||||
|
||||
callback(null);
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, atext);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Pad.prototype.getKeyRevisionNumber = function getKeyRevisionNumber(revNum) {
|
||||
return Math.floor(revNum / 100) * 100;
|
||||
};
|
||||
|
||||
Pad.prototype.text = function text() {
|
||||
return this.atext.text;
|
||||
};
|
||||
|
||||
Pad.prototype.setText = function setText(newText) {
|
||||
//clean the new text
|
||||
newText = cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
|
||||
//create the changeset
|
||||
var changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||
|
||||
//append the changeset
|
||||
this.appendRevision(changeset);
|
||||
};
|
||||
|
||||
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
|
||||
this.chatHead++;
|
||||
//save the chat entry in the database
|
||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
||||
//save the new chat head
|
||||
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
|
||||
};
|
||||
|
||||
Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, atext);
|
||||
entry = _entry;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
getKeyRevisionNumber : function(revNum)
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
return Math.floor(revNum / 100) * 100;
|
||||
},
|
||||
|
||||
text : function()
|
||||
{
|
||||
return this.atext.text;
|
||||
},
|
||||
|
||||
setText : function(newText)
|
||||
{
|
||||
//clean the new text
|
||||
newText = exports.cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
|
||||
//create the changeset
|
||||
var changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||
|
||||
//append the changeset
|
||||
this.appendRevision(changeset);
|
||||
},
|
||||
|
||||
appendChatMessage: function(text, userId, time)
|
||||
{
|
||||
this.chatHead++;
|
||||
//save the chat entry in the database
|
||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
||||
//save the new chat head
|
||||
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
|
||||
},
|
||||
|
||||
getChatMessage: function(entryNum, callback)
|
||||
{
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry = _entry;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
//this chat message doesn't exist, return null
|
||||
if(entry == null)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry.userName = authorName;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
//this chat message doesn't exist, return null
|
||||
if(!entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, entry);
|
||||
});
|
||||
},
|
||||
|
||||
getLastChatMessages: function(count, callback)
|
||||
{
|
||||
//return an empty array if there are no chat messages
|
||||
if(this.chatHead == -1)
|
||||
{
|
||||
callback(null, []);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
//works only if we decrement the amount, for some reason
|
||||
count--;
|
||||
|
||||
//set the startpoint
|
||||
var start = this.chatHead-count;
|
||||
if(start < 0)
|
||||
start = 0;
|
||||
|
||||
//set the endpoint
|
||||
var end = this.chatHead;
|
||||
|
||||
//collect the numbers of chat entries and in which order we need them
|
||||
var neededEntries = [];
|
||||
var order = 0;
|
||||
for(var i=start;i<=end; i++)
|
||||
{
|
||||
neededEntries.push({entryNum:i, order: order});
|
||||
order++;
|
||||
}
|
||||
|
||||
//get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entries[entryObject.order] = entry;
|
||||
callback();
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//sort out broken chat entries
|
||||
//it looks like in happend in the past that the chat head was
|
||||
//incremented, but the chat message wasn't added
|
||||
var cleanedEntries = [];
|
||||
for(var i=0;i<entries.length;i++)
|
||||
{
|
||||
if(entries[i]!=null)
|
||||
cleanedEntries.push(entries[i]);
|
||||
else
|
||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||
}
|
||||
|
||||
callback(null, cleanedEntries);
|
||||
});
|
||||
},
|
||||
|
||||
init : function (text, callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
||||
//replace text with default text if text isn't set
|
||||
if(text == null)
|
||||
{
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
//try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//if this pad exists, load it
|
||||
if(value != null)
|
||||
{
|
||||
_this.head = value.head;
|
||||
_this.atext = value.atext;
|
||||
_this.pool = _this.pool.fromJsonable(value.pool);
|
||||
|
||||
//ensure we have a local chatHead variable
|
||||
if(value.chatHead != null)
|
||||
_this.chatHead = value.chatHead;
|
||||
else
|
||||
_this.chatHead = -1;
|
||||
|
||||
//ensure we have a local publicStatus variable
|
||||
if(value.publicStatus != null)
|
||||
_this.publicStatus = value.publicStatus;
|
||||
else
|
||||
_this.publicStatus = false;
|
||||
|
||||
//ensure we have a local passwordHash variable
|
||||
if(value.passwordHash != null)
|
||||
_this.passwordHash = value.passwordHash;
|
||||
else
|
||||
_this.passwordHash = null;
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
},
|
||||
remove: function(callback)
|
||||
{
|
||||
var padID = this.id;
|
||||
var _this = this;
|
||||
|
||||
//kick everyone from this pad
|
||||
padMessageHandler.kickSessionsFromPad(padID);
|
||||
|
||||
async.series([
|
||||
//delete all relations
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//is it a group pad? -> delete the entry of this pad in the group
|
||||
function(callback)
|
||||
{
|
||||
//is it a group pad?
|
||||
if(padID.indexOf("$")!=-1)
|
||||
{
|
||||
var groupID = padID.substring(0,padID.indexOf("$"));
|
||||
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//remove the pad entry
|
||||
delete group.pads[padID];
|
||||
|
||||
//set the new value
|
||||
db.set("group:" + groupID, group);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
//its no group pad, nothing to do here
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
},
|
||||
//remove the readonly entries
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
db.remove("pad2readonly:" + padID);
|
||||
db.remove("readonly2pad:" + readonlyID);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//delete all chat messages
|
||||
function(callback)
|
||||
{
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":chat:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
//delete all revisions
|
||||
function(callback)
|
||||
{
|
||||
var revHead = _this.head;
|
||||
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":revs:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//delete the pad entry and delete pad from padManager
|
||||
function(callback)
|
||||
{
|
||||
db.remove("pad:"+padID);
|
||||
padManager.unloadPad(padID);
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry.userName = authorName;
|
||||
callback();
|
||||
})
|
||||
},
|
||||
//set in db
|
||||
setPublicStatus: function(publicStatus)
|
||||
{
|
||||
this.publicStatus = publicStatus;
|
||||
db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
|
||||
},
|
||||
setPassword: function(password)
|
||||
{
|
||||
this.passwordHash = password == null ? null : hash(password, generateSalt());
|
||||
db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
|
||||
},
|
||||
isCorrectPassword: function(password)
|
||||
{
|
||||
return compare(this.passwordHash, password)
|
||||
},
|
||||
isPasswordProtected: function()
|
||||
{
|
||||
return this.passwordHash != null;
|
||||
});
|
||||
}
|
||||
}, // methods
|
||||
});
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, entry);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback) {
|
||||
//return an empty array if there are no chat messages
|
||||
if(this.chatHead == -1)
|
||||
{
|
||||
callback(null, []);
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
//works only if we decrement the amount, for some reason
|
||||
count--;
|
||||
|
||||
//set the startpoint
|
||||
var start = this.chatHead-count;
|
||||
if(start < 0)
|
||||
start = 0;
|
||||
|
||||
//set the endpoint
|
||||
var end = this.chatHead;
|
||||
|
||||
//collect the numbers of chat entries and in which order we need them
|
||||
var neededEntries = [];
|
||||
var order = 0;
|
||||
for(var i=start;i<=end; i++)
|
||||
{
|
||||
neededEntries.push({entryNum:i, order: order});
|
||||
order++;
|
||||
}
|
||||
|
||||
//get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entries[entryObject.order] = entry;
|
||||
callback();
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//sort out broken chat entries
|
||||
//it looks like in happend in the past that the chat head was
|
||||
//incremented, but the chat message wasn't added
|
||||
var cleanedEntries = [];
|
||||
for(var i=0;i<entries.length;i++)
|
||||
{
|
||||
if(entries[i]) {
|
||||
cleanedEntries.push(entries[i]);
|
||||
}
|
||||
else
|
||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||
}
|
||||
|
||||
callback(null, cleanedEntries);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.init = function init(text, callback) {
|
||||
var _this = this;
|
||||
|
||||
//replace text with default text if text isn't set
|
||||
if(!text)
|
||||
{
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
//try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//if this pad exists, load it
|
||||
if(value)
|
||||
{
|
||||
_this.head = value.head;
|
||||
_this.atext = value.atext;
|
||||
_this.pool = _this.pool.fromJsonable(value.pool);
|
||||
|
||||
//ensure we have a local chatHead variable
|
||||
if(value.chatHead) {
|
||||
_this.chatHead = value.chatHead;
|
||||
}
|
||||
else {
|
||||
_this.chatHead = -1;
|
||||
}
|
||||
//ensure we have a local publicStatus variable
|
||||
if(value.publicStatus) {
|
||||
_this.publicStatus = value.publicStatus;
|
||||
}
|
||||
else {
|
||||
_this.publicStatus = false;
|
||||
}
|
||||
//ensure we have a local passwordHash variable
|
||||
if(value.passwordHash) {
|
||||
_this.passwordHash = value.passwordHash;
|
||||
}
|
||||
else {
|
||||
_this.passwordHash = null;
|
||||
}
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, cleanText(text));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.remove = function remove(callback) {
|
||||
var padID = this.id;
|
||||
var _this = this;
|
||||
|
||||
//kick everyone from this pad
|
||||
padMessageHandler.kickSessionsFromPad(padID);
|
||||
|
||||
async.series([
|
||||
//delete all relations
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//is it a group pad? -> delete the entry of this pad in the group
|
||||
function(callback)
|
||||
{
|
||||
//is it a group pad?
|
||||
if(padID.indexOf("$")!=-1)
|
||||
{
|
||||
var groupID = padID.substring(0,padID.indexOf("$"));
|
||||
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//remove the pad entry
|
||||
delete group.pads[padID];
|
||||
|
||||
//set the new value
|
||||
db.set("group:" + groupID, group);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
//its no group pad, nothing to do here
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
},
|
||||
//remove the readonly entries
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
db.remove("pad2readonly:" + padID);
|
||||
db.remove("readonly2pad:" + readonlyID);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//delete all chat messages
|
||||
function(callback)
|
||||
{
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":chat:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
//delete all revisions
|
||||
function(callback)
|
||||
{
|
||||
var revHead = _this.head;
|
||||
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":revs:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//delete the pad entry and delete pad from padManager
|
||||
function(callback)
|
||||
{
|
||||
db.remove("pad:"+padID);
|
||||
padManager.unloadPad(padID);
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
//set in db
|
||||
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
||||
this.publicStatus = publicStatus;
|
||||
db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
|
||||
};
|
||||
|
||||
Pad.prototype.setPassword = function setPassword(password) {
|
||||
this.passwordHash = password ? hash(password, generateSalt()) : null;
|
||||
db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
|
||||
};
|
||||
|
||||
Pad.isCorrectPassword = function isCorrectPassword(password) {
|
||||
return compare(this.passwordHash, password);
|
||||
};
|
||||
|
||||
Pad.isPasswordProtected = function isPasswordProtected() {
|
||||
return this.passwordHash ? true: false;
|
||||
};
|
||||
|
||||
|
||||
/* Crypto helper methods */
|
||||
|
||||
|
@ -531,5 +495,5 @@ function generateSalt()
|
|||
|
||||
function compare(hashStr, password)
|
||||
{
|
||||
return hash(password, hashStr.split("$")[1]) === hashStr;
|
||||
return hash(password, hashStr.split("$")[1]) === hashStr;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
require("../db/Pad");
|
||||
var Pad = require("../db/Pad").Pad;
|
||||
var db = require("./DB").db;
|
||||
|
||||
/**
|
||||
/**
|
||||
* An Object containing all known Pads. Provides "get" and "set" functions,
|
||||
* which should be used instead of indexing with brackets. These prepend a
|
||||
* colon to the key, to avoid conflicting with built-in Object methods or with
|
||||
|
@ -41,26 +41,26 @@ var globalPads = {
|
|||
/**
|
||||
* Returns a Pad Object with the callback
|
||||
* @param id A String with the id of the pad
|
||||
* @param {Function} callback
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.getPad = function(id, text, callback)
|
||||
{
|
||||
{
|
||||
//check if this is a valid padId
|
||||
if(!exports.isValidPadId(id))
|
||||
{
|
||||
callback(new customError(id + " is not a valid padId","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//make text an optional parameter
|
||||
if(typeof text == "function")
|
||||
if(typeof text === "function")
|
||||
{
|
||||
callback = text;
|
||||
text = null;
|
||||
}
|
||||
|
||||
|
||||
//check if this is a valid text
|
||||
if(text != null)
|
||||
if(text)
|
||||
{
|
||||
//check if text is a string
|
||||
if(typeof text != "string")
|
||||
|
@ -68,7 +68,7 @@ exports.getPad = function(id, text, callback)
|
|||
callback(new customError("text is not a string","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//check if text is less than 100k chars
|
||||
if(text.length > 100000)
|
||||
{
|
||||
|
@ -76,11 +76,11 @@ exports.getPad = function(id, text, callback)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var pad = globalPads.get(id);
|
||||
|
||||
|
||||
//return pad if its already loaded
|
||||
if(pad != null)
|
||||
if(pad)
|
||||
{
|
||||
callback(null, pad);
|
||||
}
|
||||
|
@ -88,17 +88,17 @@ exports.getPad = function(id, text, callback)
|
|||
else
|
||||
{
|
||||
pad = new Pad(id);
|
||||
|
||||
|
||||
//initalize the pad
|
||||
pad.init(text, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
globalPads.set(id, pad);
|
||||
callback(null, pad);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//checks if a pad exists
|
||||
exports.doesPadExists = function(padId, callback)
|
||||
|
@ -106,18 +106,18 @@ exports.doesPadExists = function(padId, callback)
|
|||
db.get("pad:"+padId, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, value != null);
|
||||
callback(null, value ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.isValidPadId = function(padId)
|
||||
{
|
||||
return /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId);
|
||||
}
|
||||
return (/^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/).test(padId);
|
||||
};
|
||||
|
||||
//removes a pad from the array
|
||||
exports.unloadPad = function(padId)
|
||||
{
|
||||
if(globalPads.get(padId))
|
||||
globalPads.remove(padId);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,9 +27,9 @@ var async = require("async");
|
|||
* @param {String} padId the id of the pad
|
||||
*/
|
||||
exports.getReadOnlyId = function (padId, callback)
|
||||
{
|
||||
{
|
||||
var readOnlyId;
|
||||
|
||||
|
||||
async.waterfall([
|
||||
//check if there is a pad2readonly entry
|
||||
function(callback)
|
||||
|
@ -39,10 +39,10 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
function(dbReadOnlyId, callback)
|
||||
{
|
||||
//there is no readOnly Entry in the database, let's create one
|
||||
if(dbReadOnlyId == null)
|
||||
if(!dbReadOnlyId)
|
||||
{
|
||||
readOnlyId = "r." + randomString(16);
|
||||
|
||||
|
||||
db.set("pad2readonly:" + padId, readOnlyId);
|
||||
db.set("readonly2pad:" + readOnlyId, padId);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
{
|
||||
readOnlyId = dbReadOnlyId;
|
||||
}
|
||||
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
|
@ -59,8 +59,8 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
//return the results
|
||||
callback(null, readOnlyId);
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a the padId for a read only id
|
||||
|
@ -69,12 +69,12 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
exports.getPadId = function(readOnlyId, callback)
|
||||
{
|
||||
db.get("readonly2pad:" + readOnlyId, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the read only ids
|
||||
*/
|
||||
function randomString(len)
|
||||
function randomString(len)
|
||||
{
|
||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
var randomstring = '';
|
||||
|
|
|
@ -24,18 +24,18 @@ var async = require("async");
|
|||
var authorManager = require("./AuthorManager");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
var settings = require("../utils/Settings")
|
||||
var settings = require("../utils/Settings");
|
||||
|
||||
/**
|
||||
* This function controlls the access to a pad, it checks if the user can access a pad.
|
||||
* @param padID the pad the user wants to access
|
||||
* @param sesssionID the session the user has (set via api)
|
||||
* @param token the token of the author (randomly generated at client side, used for public pads)
|
||||
* @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})
|
||||
*/
|
||||
*/
|
||||
exports.checkAccess = function (padID, sessionID, token, password, callback)
|
||||
{
|
||||
{
|
||||
var statusObject;
|
||||
|
||||
// a valid session is required (api-only mode)
|
||||
|
@ -58,7 +58,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
authorManager.getAuthor4Token(token, function(err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
// assume user has access
|
||||
statusObject = {accessStatus: "grant", authorID: author};
|
||||
// user can't create pads
|
||||
|
@ -68,7 +68,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
// pad doesn't exist - user can't have access
|
||||
if(!exists) statusObject.accessStatus = "deny";
|
||||
// grant or deny access, with author of token
|
||||
|
@ -81,13 +81,13 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
// grant access, with author of token
|
||||
callback(null, statusObject);
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
//don't continue
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var groupID = padID.split("$")[0];
|
||||
var padExists = false;
|
||||
var validSession = false;
|
||||
|
@ -95,10 +95,10 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
var tokenAuthor;
|
||||
var isPublic;
|
||||
var isPasswordProtected;
|
||||
var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
||||
var passwordStatus = password === null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
||||
|
||||
async.series([
|
||||
//get basic informations from the database
|
||||
//get basic informations from the database
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
|
@ -123,19 +123,19 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
var now = Math.floor(new Date().getTime()/1000);
|
||||
|
||||
|
||||
//is it for this group? and is validUntil still ok? --> validSession
|
||||
if(sessionInfo.groupID == groupID && sessionInfo.validUntil > now)
|
||||
{
|
||||
validSession = true;
|
||||
}
|
||||
|
||||
|
||||
sessionAuthor = sessionInfo.authorID;
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
@ -156,28 +156,28 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
function(callback)
|
||||
{
|
||||
//skip this if the pad doesn't exists
|
||||
if(padExists == false)
|
||||
if(!padExists)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
padManager.getPad(padID, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//is it a public pad?
|
||||
isPublic = pad.getPublicStatus();
|
||||
|
||||
|
||||
//is it password protected?
|
||||
isPasswordProtected = pad.isPasswordProtected();
|
||||
|
||||
|
||||
//is password correct?
|
||||
if(isPasswordProtected && password && pad.isCorrectPassword(password))
|
||||
{
|
||||
passwordStatus = "correct";
|
||||
}
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
@ -214,7 +214,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
{
|
||||
throw new Error("Ops, something wrong happend");
|
||||
}
|
||||
}
|
||||
}
|
||||
//- a valid session for this group avaible but pad doesn't exists
|
||||
else if(validSession && !padExists)
|
||||
{
|
||||
|
@ -238,7 +238,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
//--> grant access, with author of token
|
||||
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
||||
}
|
||||
//- its public and the pad is password protected but wrong password given
|
||||
//- its 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
|
||||
|
@ -260,14 +260,14 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
{
|
||||
throw new Error("Ops, something wrong happend");
|
||||
}
|
||||
}
|
||||
}
|
||||
// there is no valid session avaiable AND pad doesn't exists
|
||||
else
|
||||
{
|
||||
//--> deny access
|
||||
statusObject = {accessStatus: "deny"};
|
||||
}
|
||||
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
|
@ -275,4 +275,4 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback(null, statusObject);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,24 +17,24 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var groupMangager = require("./GroupManager");
|
||||
var authorMangager = require("./AuthorManager");
|
||||
|
||||
|
||||
exports.doesSessionExist = function(sessionID, callback)
|
||||
{
|
||||
//check if the database entry of this session exists
|
||||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, session != null);
|
||||
callback(null, session ? true : false);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new session between an author and a group
|
||||
*/
|
||||
|
@ -49,9 +49,9 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
groupMangager.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -68,9 +68,9 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
authorMangager.doesAuthorExists(authorID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//author does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("authorID does not exist","apierror"));
|
||||
}
|
||||
|
@ -88,9 +88,9 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(typeof validUntil != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(validUntil)))
|
||||
if(!isNaN(parseInt(validUntil, 10)))
|
||||
{
|
||||
validUntil = parseInt(validUntil);
|
||||
validUntil = parseInt(validUntil, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -98,34 +98,34 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(validUntil < 0)
|
||||
{
|
||||
callback(new customError("validUntil is a negativ number","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//ensure this is not a float value
|
||||
if(!is_int(validUntil))
|
||||
{
|
||||
callback(new customError("validUntil is a float value","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//check if validUntil is in the future
|
||||
if(Math.floor(new Date().getTime()/1000) > validUntil)
|
||||
{
|
||||
callback(new customError("validUntil is in the past","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//generate sessionID
|
||||
sessionID = "s." + randomString(16);
|
||||
|
||||
|
||||
//set the session into the database
|
||||
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
||||
|
||||
|
||||
callback();
|
||||
},
|
||||
//set the group2sessions entry
|
||||
|
@ -135,19 +135,19 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
db.get("group2sessions:" + groupID, function(err, group2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//the entry doesn't exist so far, let's create it
|
||||
if(group2sessions == null)
|
||||
if(!group2sessions)
|
||||
{
|
||||
group2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
|
||||
//add the entry for this session
|
||||
group2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
|
||||
//save the new element back
|
||||
db.set("group2sessions:" + groupID, group2sessions);
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
@ -158,30 +158,30 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
db.get("author2sessions:" + authorID, function(err, author2sessions)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//the entry doesn't exist so far, let's create it
|
||||
if(author2sessions == null)
|
||||
if(!author2sessions)
|
||||
{
|
||||
author2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
|
||||
//add the entry for this session
|
||||
author2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
|
||||
//save the new element back
|
||||
db.set("author2sessions:" + authorID, author2sessions);
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//return error and sessionID
|
||||
callback(null, {sessionID: sessionID});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getSessionInfo = function(sessionID, callback)
|
||||
{
|
||||
|
@ -189,11 +189,11 @@ exports.getSessionInfo = function(sessionID, callback)
|
|||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
if(session === null)
|
||||
{
|
||||
callback(new customError("sessionID does not exist","apierror"))
|
||||
callback(new customError("sessionID does not exist","apierror"));
|
||||
}
|
||||
//everything is fine, return the sessioninfos
|
||||
else
|
||||
|
@ -201,7 +201,7 @@ exports.getSessionInfo = function(sessionID, callback)
|
|||
callback(null, session);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a session
|
||||
|
@ -218,18 +218,18 @@ exports.deleteSession = function(sessionID, callback)
|
|||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
if(!session)
|
||||
{
|
||||
callback(new customError("sessionID does not exist","apierror"))
|
||||
callback(new customError("sessionID does not exist","apierror"));
|
||||
}
|
||||
//everything is fine, return the sessioninfos
|
||||
else
|
||||
{
|
||||
authorID = session.authorID;
|
||||
groupID = session.groupID;
|
||||
|
||||
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
@ -259,32 +259,32 @@ exports.deleteSession = function(sessionID, callback)
|
|||
{
|
||||
//remove the session
|
||||
db.remove("session:" + sessionID);
|
||||
|
||||
|
||||
//remove session from group2sessions
|
||||
delete group2sessions.sessionIDs[sessionID];
|
||||
db.set("group2sessions:" + groupID, group2sessions);
|
||||
|
||||
|
||||
//remove session from author2sessions
|
||||
delete author2sessions.sessionIDs[sessionID];
|
||||
db.set("author2sessions:" + authorID, author2sessions);
|
||||
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.listSessionsOfGroup = function(groupID, callback)
|
||||
{
|
||||
groupMangager.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -294,16 +294,16 @@ exports.listSessionsOfGroup = function(groupID, callback)
|
|||
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.listSessionsOfAuthor = function(authorID, callback)
|
||||
{
|
||||
{
|
||||
authorMangager.doesAuthorExists(authorID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("authorID does not exist","apierror"));
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ exports.listSessionsOfAuthor = function(authorID, callback)
|
|||
listSessionsWithDBKey("author2sessions:" + authorID, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//this function is basicly the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
function listSessionsWithDBKey (dbkey, callback)
|
||||
|
@ -332,14 +332,14 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
});
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
{
|
||||
//collect all sessionIDs in an arrary
|
||||
var sessionIDs = [];
|
||||
for (var i in sessions)
|
||||
{
|
||||
sessionIDs.push(i);
|
||||
}
|
||||
|
||||
|
||||
//foreach trough the sessions and get the sessioninfos
|
||||
async.forEach(sessionIDs, function(sessionID, callback)
|
||||
{
|
||||
|
@ -361,7 +361,7 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the SessionIDs
|
||||
*/
|
||||
function randomString(len)
|
||||
function randomString(len)
|
||||
{
|
||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
var randomstring = '';
|
||||
|
@ -375,6 +375,6 @@ function randomString(len)
|
|||
|
||||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue