mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-22 00:16:15 -04:00
created a folder structure in node
This commit is contained in:
parent
115f7d6b51
commit
8736b945c3
16 changed files with 0 additions and 0 deletions
135
node/db/AuthorManager.js
Normal file
135
node/db/AuthorManager.js
Normal file
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* The AuthorManager controlls all information about the Pad authors
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var db = require("./db").db;
|
||||
var async = require("async");
|
||||
|
||||
/**
|
||||
* Returns the Author Id for a token. If the token is unkown,
|
||||
* it creates a author for the token
|
||||
* @param {String} token The token
|
||||
* @param {Function} callback callback (err, author)
|
||||
* The callback function that is called when the result is here
|
||||
*/
|
||||
exports.getAuthor4Token = function (token, callback)
|
||||
{
|
||||
var author;
|
||||
|
||||
async.waterfall([
|
||||
//try to get the author for this token
|
||||
function(callback)
|
||||
{
|
||||
db.get("token2author:" + token, callback);
|
||||
},
|
||||
function(value, callback)
|
||||
{
|
||||
//there is no author with this token, so create one
|
||||
if(value == null)
|
||||
{
|
||||
//create the new author name
|
||||
author = "g." + _randomString(16);
|
||||
|
||||
//set the token2author db entry
|
||||
db.set("token2author:" + token, author);
|
||||
|
||||
//set the globalAuthors db entry
|
||||
var authorObj = {colorId : Math.floor(Math.random()*32), name: null, timestamp: new Date().getTime()};
|
||||
db.set("globalAuthor:" + author, authorObj);
|
||||
|
||||
callback(null);
|
||||
}
|
||||
//there is a author with this token
|
||||
else
|
||||
{
|
||||
author = value;
|
||||
|
||||
//update the author time
|
||||
db.setSub("globalAuthor:" + author, ["timestamp"], new Date().getTime());
|
||||
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
callback(err, author);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Author Obj of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {Function} callback callback(err, authorObj)
|
||||
*/
|
||||
exports.getAuthor = function (author, callback)
|
||||
{
|
||||
db.get("globalAuthor:" + author, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color Id of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {Function} callback callback(err, colorId)
|
||||
*/
|
||||
exports.getAuthorColorId = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color Id of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {Function} callback (optional)
|
||||
*/
|
||||
exports.setAuthorColorId = function (author, colorId, callback)
|
||||
{
|
||||
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {Function} callback callback(err, name)
|
||||
*/
|
||||
exports.getAuthorName = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["name"], callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {Function} callback (optional)
|
||||
*/
|
||||
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) {
|
||||
// use only numbers and lowercase letters
|
||||
var pieces = [];
|
||||
for(var i=0;i<len;i++) {
|
||||
pieces.push(Math.floor(Math.random()*36).toString(36).slice(-1));
|
||||
}
|
||||
return pieces.join('');
|
||||
}
|
56
node/db/DB.js
Normal file
56
node/db/DB.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* The DB Module provides a database initalized with the settings
|
||||
* provided by the settings module
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var ueberDB = require("ueberDB");
|
||||
var settings = require("./settings");
|
||||
|
||||
//set database settings
|
||||
var db = new ueberDB.database(settings.dbType, settings.dbSettings);
|
||||
|
||||
/**
|
||||
* The UeberDB Object that provides the database functions
|
||||
*/
|
||||
exports.db = null;
|
||||
|
||||
/**
|
||||
* Initalizes the database with the settings provided by the settings module
|
||||
* @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
|
||||
if(err)
|
||||
{
|
||||
console.error("ERROR: Problem while initalizing the database");
|
||||
console.error(err.stack ? err.stack : err);
|
||||
process.exit(1);
|
||||
}
|
||||
//everything ok
|
||||
else
|
||||
{
|
||||
exports.db = db;
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
339
node/db/Pad.js
Normal file
339
node/db/Pad.js
Normal file
|
@ -0,0 +1,339 @@
|
|||
/**
|
||||
* The pad object, defined with joose
|
||||
*/
|
||||
|
||||
var Changeset = require("../Changeset");
|
||||
var AttributePoolFactory = require("../AttributePoolFactory");
|
||||
var db = require("../db").db;
|
||||
var async = require("async");
|
||||
var settings = require('../settings');
|
||||
var authorManager = require("../AuthorManager");
|
||||
|
||||
/**
|
||||
* 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, ' ');
|
||||
}
|
||||
|
||||
Class('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
|
||||
|
||||
id : { is : 'r' }
|
||||
},
|
||||
|
||||
methods : {
|
||||
|
||||
BUILD : function (id)
|
||||
{
|
||||
return {
|
||||
'id' : id,
|
||||
}
|
||||
},
|
||||
|
||||
appendRevision : function(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});
|
||||
}, //appendRevision
|
||||
|
||||
getRevisionChangeset : function(revNum, 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] != "")
|
||||
{
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
}
|
||||
}
|
||||
|
||||
return authors;
|
||||
},
|
||||
|
||||
getInternalRevisionAText : function(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)
|
||||
{
|
||||
async.parallel([
|
||||
//get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
//get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
changesets[item] = changeset;
|
||||
callback(err);
|
||||
});
|
||||
}, 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(err, atext);
|
||||
});
|
||||
},
|
||||
|
||||
getKeyRevisionNumber : function(revNum)
|
||||
{
|
||||
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, withName, callback)
|
||||
{
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
entry = _entry;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
//skip if we don't need the authorName
|
||||
if(!withName)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
entry.userName = authorName;
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
callback(err, entry);
|
||||
});
|
||||
},
|
||||
|
||||
getLastChatMessages: function(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, true, function(err, entry)
|
||||
{
|
||||
entries[entryObject.order] = entry;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
callback(err, entries);
|
||||
});
|
||||
},
|
||||
|
||||
init : function (callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
||||
//try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
callback(err, null);
|
||||
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);
|
||||
|
||||
if(value.chatHead != null)
|
||||
_this.chatHead = value.chatHead;
|
||||
else
|
||||
_this.chatHead = -1;
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(settings.defaultPadText));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
}, // methods
|
||||
});
|
63
node/db/PadManager.js
Normal file
63
node/db/PadManager.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* The Pad Manager is a Factory for pad Objects
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Changeset = require("./Models/Pad");
|
||||
|
||||
/**
|
||||
* A Array with all known Pads
|
||||
*/
|
||||
globalPads = [];
|
||||
|
||||
/**
|
||||
* Returns a Pad Object with the callback
|
||||
* @param id A String with the id of the pad
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.getPad = function(id, callback)
|
||||
{
|
||||
var pad = globalPads[id];
|
||||
|
||||
//return pad if its already loaded
|
||||
if(pad != null)
|
||||
{
|
||||
callback(null, pad);
|
||||
}
|
||||
//try to load pad
|
||||
else
|
||||
{
|
||||
pad = new Pad(id);
|
||||
|
||||
//initalize the pad
|
||||
pad.init(function(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
callback(err, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
globalPads[id] = pad;
|
||||
callback(null, pad);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//globalPads[id].timestamp = new Date().getTime();
|
||||
}
|
83
node/db/ReadOnlyManager.js
Normal file
83
node/db/ReadOnlyManager.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* The ReadOnlyManager manages the database and rendering releated to read only pads
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var db = require("./db").db;
|
||||
var async = require("async");
|
||||
|
||||
/**
|
||||
* returns a read only id for a pad
|
||||
* @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)
|
||||
{
|
||||
db.get("pad2readonly:" + padId, callback);
|
||||
},
|
||||
function(dbReadOnlyId, callback)
|
||||
{
|
||||
//there is no readOnly Entry in the database, let's create one
|
||||
if(dbReadOnlyId == null)
|
||||
{
|
||||
readOnlyId = randomString(10);
|
||||
|
||||
db.set("pad2readonly:" + padId, readOnlyId);
|
||||
db.set("readonly2pad:" + readOnlyId, padId);
|
||||
}
|
||||
//there is a readOnly Entry in the database, let's take this one
|
||||
else
|
||||
{
|
||||
readOnlyId = dbReadOnlyId;
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
//return the results
|
||||
callback(err, readOnlyId);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a the padId for a read only id
|
||||
* @param {String} readOnlyId read only id
|
||||
*/
|
||||
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)
|
||||
{
|
||||
// use only numbers and lowercase letters
|
||||
var pieces = [];
|
||||
for(var i=0;i<len;i++) {
|
||||
pieces.push(Math.floor(Math.random()*36).toString(36).slice(-1));
|
||||
}
|
||||
return pieces.join('');
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue