mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-22 00:16:15 -04:00
lint: Run eslint --fix
on src/
This commit is contained in:
parent
b8d07a42eb
commit
8e5fd19db2
109 changed files with 9061 additions and 10572 deletions
|
@ -18,19 +18,19 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||
var customError = require("../utils/customError");
|
||||
var padManager = require("./PadManager");
|
||||
var padMessageHandler = require("../handler/PadMessageHandler");
|
||||
var readOnlyManager = require("./ReadOnlyManager");
|
||||
var groupManager = require("./GroupManager");
|
||||
var authorManager = require("./AuthorManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
var exportHtml = require("../utils/ExportHtml");
|
||||
var exportTxt = require("../utils/ExportTxt");
|
||||
var importHtml = require("../utils/ImportHtml");
|
||||
var cleanText = require("./Pad").cleanText;
|
||||
var PadDiff = require("../utils/padDiff");
|
||||
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||
const customError = require('../utils/customError');
|
||||
const padManager = require('./PadManager');
|
||||
const padMessageHandler = require('../handler/PadMessageHandler');
|
||||
const readOnlyManager = require('./ReadOnlyManager');
|
||||
const groupManager = require('./GroupManager');
|
||||
const authorManager = require('./AuthorManager');
|
||||
const sessionManager = require('./SessionManager');
|
||||
const exportHtml = require('../utils/ExportHtml');
|
||||
const exportTxt = require('../utils/ExportTxt');
|
||||
const importHtml = require('../utils/ImportHtml');
|
||||
const cleanText = require('./Pad').cleanText;
|
||||
const PadDiff = require('../utils/padDiff');
|
||||
|
||||
/* ********************
|
||||
* GROUP FUNCTIONS ****
|
||||
|
@ -101,10 +101,10 @@ Example returns:
|
|||
}
|
||||
|
||||
*/
|
||||
exports.getAttributePool = async function(padID) {
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { pool: pad.pool };
|
||||
}
|
||||
exports.getAttributePool = async function (padID) {
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {pool: pad.pool};
|
||||
};
|
||||
|
||||
/**
|
||||
getRevisionChangeset (padID, [rev])
|
||||
|
@ -119,22 +119,21 @@ Example returns:
|
|||
}
|
||||
|
||||
*/
|
||||
exports.getRevisionChangeset = async function(padID, rev) {
|
||||
exports.getRevisionChangeset = async function (padID, rev) {
|
||||
// try to parse the revision number
|
||||
if (rev !== undefined) {
|
||||
rev = checkValidRev(rev);
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
let head = pad.getHeadRevisionNumber();
|
||||
const pad = await getPadSafe(padID, true);
|
||||
const head = pad.getHeadRevisionNumber();
|
||||
|
||||
// the client asked for a special revision
|
||||
if (rev !== undefined) {
|
||||
|
||||
// check if this is a valid revision
|
||||
if (rev > head) {
|
||||
throw new customError("rev is higher than the head revision of the pad", "apierror");
|
||||
throw new customError('rev is higher than the head revision of the pad', 'apierror');
|
||||
}
|
||||
|
||||
// get the changeset for this revision
|
||||
|
@ -143,7 +142,7 @@ exports.getRevisionChangeset = async function(padID, rev) {
|
|||
|
||||
// the client wants the latest changeset, lets return it to him
|
||||
return pad.getRevisionChangeset(head);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getText(padID, [rev]) returns the text of a pad
|
||||
|
@ -153,33 +152,32 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {text:"Welcome Text"}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getText = async function(padID, rev) {
|
||||
exports.getText = async function (padID, rev) {
|
||||
// try to parse the revision number
|
||||
if (rev !== undefined) {
|
||||
rev = checkValidRev(rev);
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
let head = pad.getHeadRevisionNumber();
|
||||
const pad = await getPadSafe(padID, true);
|
||||
const head = pad.getHeadRevisionNumber();
|
||||
|
||||
// the client asked for a special revision
|
||||
if (rev !== undefined) {
|
||||
|
||||
// check if this is a valid revision
|
||||
if (rev > head) {
|
||||
throw new customError("rev is higher than the head revision of the pad", "apierror");
|
||||
throw new customError('rev is higher than the head revision of the pad', 'apierror');
|
||||
}
|
||||
|
||||
// get the text of this revision
|
||||
let text = await pad.getInternalRevisionAText(rev);
|
||||
return { text };
|
||||
const text = await pad.getInternalRevisionAText(rev);
|
||||
return {text};
|
||||
}
|
||||
|
||||
// the client wants the latest text, lets return it to him
|
||||
let text = exportTxt.getTXTFromAtext(pad, pad.atext);
|
||||
return { text };
|
||||
}
|
||||
const text = exportTxt.getTXTFromAtext(pad, pad.atext);
|
||||
return {text};
|
||||
};
|
||||
|
||||
/**
|
||||
setText(padID, text) sets the text of a pad
|
||||
|
@ -190,20 +188,20 @@ Example returns:
|
|||
{code: 1, message:"padID does not exist", data: null}
|
||||
{code: 1, message:"text too long", data: null}
|
||||
*/
|
||||
exports.setText = async function(padID, text) {
|
||||
exports.setText = async function (padID, text) {
|
||||
// text is required
|
||||
if (typeof text !== "string") {
|
||||
throw new customError("text is not a string", "apierror");
|
||||
if (typeof text !== 'string') {
|
||||
throw new customError('text is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
await Promise.all([
|
||||
pad.setText(text),
|
||||
padMessageHandler.updatePadClients(pad),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
appendText(padID, text) appends text to a pad
|
||||
|
@ -214,18 +212,18 @@ Example returns:
|
|||
{code: 1, message:"padID does not exist", data: null}
|
||||
{code: 1, message:"text too long", data: null}
|
||||
*/
|
||||
exports.appendText = async function(padID, text) {
|
||||
exports.appendText = async function (padID, text) {
|
||||
// text is required
|
||||
if (typeof text !== "string") {
|
||||
throw new customError("text is not a string", "apierror");
|
||||
if (typeof text !== 'string') {
|
||||
throw new customError('text is not a string', 'apierror');
|
||||
}
|
||||
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
await Promise.all([
|
||||
pad.appendText(text),
|
||||
padMessageHandler.updatePadClients(pad),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getHTML(padID, [rev]) returns the html of a pad
|
||||
|
@ -235,19 +233,19 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {text:"Welcome <strong>Text</strong>"}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getHTML = async function(padID, rev) {
|
||||
exports.getHTML = async function (padID, rev) {
|
||||
if (rev !== undefined) {
|
||||
rev = checkValidRev(rev);
|
||||
}
|
||||
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
// the client asked for a special revision
|
||||
if (rev !== undefined) {
|
||||
// check if this is a valid revision
|
||||
let head = pad.getHeadRevisionNumber();
|
||||
const head = pad.getHeadRevisionNumber();
|
||||
if (rev > head) {
|
||||
throw new customError("rev is higher than the head revision of the pad", "apierror");
|
||||
throw new customError('rev is higher than the head revision of the pad', 'apierror');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,9 +253,9 @@ exports.getHTML = async function(padID, rev) {
|
|||
let html = await exportHtml.getPadHTML(pad, rev);
|
||||
|
||||
// wrap the HTML
|
||||
html = "<!DOCTYPE HTML><html><body>" + html + "</body></html>";
|
||||
return { html };
|
||||
}
|
||||
html = `<!DOCTYPE HTML><html><body>${html}</body></html>`;
|
||||
return {html};
|
||||
};
|
||||
|
||||
/**
|
||||
setHTML(padID, html) sets the text of a pad based on HTML
|
||||
|
@ -267,20 +265,20 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.setHTML = async function(padID, html) {
|
||||
exports.setHTML = async function (padID, html) {
|
||||
// html string is required
|
||||
if (typeof html !== "string") {
|
||||
throw new customError("html is not a string", "apierror");
|
||||
if (typeof html !== 'string') {
|
||||
throw new customError('html is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
// add a new changeset with the new html to the pad
|
||||
try {
|
||||
await importHtml.setPadHTML(pad, cleanText(html));
|
||||
} catch (e) {
|
||||
throw new customError("HTML is malformed", "apierror");
|
||||
throw new customError('HTML is malformed', 'apierror');
|
||||
}
|
||||
|
||||
// update the clients on the pad
|
||||
|
@ -303,23 +301,23 @@ Example returns:
|
|||
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getChatHistory = async function(padID, start, end) {
|
||||
exports.getChatHistory = async function (padID, start, end) {
|
||||
if (start && end) {
|
||||
if (start < 0) {
|
||||
throw new customError("start is below zero", "apierror");
|
||||
throw new customError('start is below zero', 'apierror');
|
||||
}
|
||||
if (end < 0) {
|
||||
throw new customError("end is below zero", "apierror");
|
||||
throw new customError('end is below zero', 'apierror');
|
||||
}
|
||||
if (start > end) {
|
||||
throw new customError("start is higher than end", "apierror");
|
||||
throw new customError('start is higher than end', 'apierror');
|
||||
}
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
var chatHead = pad.chatHead;
|
||||
const chatHead = pad.chatHead;
|
||||
|
||||
// fall back to getting the whole chat-history if a parameter is missing
|
||||
if (!start || !end) {
|
||||
|
@ -328,17 +326,17 @@ exports.getChatHistory = async function(padID, start, end) {
|
|||
}
|
||||
|
||||
if (start > chatHead) {
|
||||
throw new customError("start is higher than the current chatHead", "apierror");
|
||||
throw new customError('start is higher than the current chatHead', 'apierror');
|
||||
}
|
||||
if (end > chatHead) {
|
||||
throw new customError("end is higher than the current chatHead", "apierror");
|
||||
throw new customError('end is higher than the current chatHead', 'apierror');
|
||||
}
|
||||
|
||||
// the the whole message-log and return it to the client
|
||||
let messages = await pad.getChatMessages(start, end);
|
||||
const messages = await pad.getChatMessages(start, end);
|
||||
|
||||
return { messages };
|
||||
}
|
||||
return {messages};
|
||||
};
|
||||
|
||||
/**
|
||||
appendChatMessage(padID, text, authorID, time), creates a chat message for the pad id, time is a timestamp
|
||||
|
@ -348,10 +346,10 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.appendChatMessage = async function(padID, text, authorID, time) {
|
||||
exports.appendChatMessage = async function (padID, text, authorID, time) {
|
||||
// text is required
|
||||
if (typeof text !== "string") {
|
||||
throw new customError("text is not a string", "apierror");
|
||||
if (typeof text !== 'string') {
|
||||
throw new customError('text is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// if time is not an integer value set time to current timestamp
|
||||
|
@ -363,7 +361,7 @@ exports.appendChatMessage = async function(padID, text, authorID, time) {
|
|||
|
||||
// save chat message to database and send message to all connected clients
|
||||
await padMessageHandler.sendChatMessageToPadClients(time, authorID, text, padID);
|
||||
}
|
||||
};
|
||||
|
||||
/* ***************
|
||||
* PAD FUNCTIONS *
|
||||
|
@ -377,11 +375,11 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {revisions: 56}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getRevisionsCount = async function(padID) {
|
||||
exports.getRevisionsCount = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { revisions: pad.getHeadRevisionNumber() };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {revisions: pad.getHeadRevisionNumber()};
|
||||
};
|
||||
|
||||
/**
|
||||
getSavedRevisionsCount(padID) returns the number of saved revisions of this pad
|
||||
|
@ -391,11 +389,11 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {savedRevisions: 42}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getSavedRevisionsCount = async function(padID) {
|
||||
exports.getSavedRevisionsCount = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { savedRevisions: pad.getSavedRevisionsNumber() };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {savedRevisions: pad.getSavedRevisionsNumber()};
|
||||
};
|
||||
|
||||
/**
|
||||
listSavedRevisions(padID) returns the list of saved revisions of this pad
|
||||
|
@ -405,11 +403,11 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {savedRevisions: [2, 42, 1337]}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.listSavedRevisions = async function(padID) {
|
||||
exports.listSavedRevisions = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { savedRevisions: pad.getSavedRevisionsList() };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {savedRevisions: pad.getSavedRevisionsList()};
|
||||
};
|
||||
|
||||
/**
|
||||
saveRevision(padID) returns the list of saved revisions of this pad
|
||||
|
@ -419,28 +417,28 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.saveRevision = async function(padID, rev) {
|
||||
exports.saveRevision = async function (padID, rev) {
|
||||
// check if rev is a number
|
||||
if (rev !== undefined) {
|
||||
rev = checkValidRev(rev);
|
||||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
let head = pad.getHeadRevisionNumber();
|
||||
const pad = await getPadSafe(padID, true);
|
||||
const head = pad.getHeadRevisionNumber();
|
||||
|
||||
// the client asked for a special revision
|
||||
if (rev !== undefined) {
|
||||
if (rev > head) {
|
||||
throw new customError("rev is higher than the head revision of the pad", "apierror");
|
||||
throw new customError('rev is higher than the head revision of the pad', 'apierror');
|
||||
}
|
||||
} else {
|
||||
rev = pad.getHeadRevisionNumber();
|
||||
}
|
||||
|
||||
let author = await authorManager.createAuthor('API');
|
||||
const author = await authorManager.createAuthor('API');
|
||||
await pad.addSavedRevision(rev, author.authorID, 'Saved through API call');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getLastEdited(padID) returns the timestamp of the last revision of the pad
|
||||
|
@ -450,12 +448,12 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {lastEdited: 1340815946602}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getLastEdited = async function(padID) {
|
||||
exports.getLastEdited = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
let lastEdited = await pad.getLastEdit();
|
||||
return { lastEdited };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
const lastEdited = await pad.getLastEdit();
|
||||
return {lastEdited};
|
||||
};
|
||||
|
||||
/**
|
||||
createPad(padName [, text]) creates a new pad in this group
|
||||
|
@ -465,22 +463,22 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"pad does already exist", data: null}
|
||||
*/
|
||||
exports.createPad = async function(padID, text) {
|
||||
exports.createPad = async function (padID, text) {
|
||||
if (padID) {
|
||||
// ensure there is no $ in the padID
|
||||
if (padID.indexOf("$") !== -1) {
|
||||
throw new customError("createPad can't create group pads", "apierror");
|
||||
if (padID.indexOf('$') !== -1) {
|
||||
throw new customError("createPad can't create group pads", 'apierror');
|
||||
}
|
||||
|
||||
// check for url special characters
|
||||
if (padID.match(/(\/|\?|&|#)/)) {
|
||||
throw new customError("malformed padID: Remove special characters", "apierror");
|
||||
throw new customError('malformed padID: Remove special characters', 'apierror');
|
||||
}
|
||||
}
|
||||
|
||||
// create pad
|
||||
await getPadSafe(padID, false, text);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
deletePad(padID) deletes a pad
|
||||
|
@ -490,10 +488,10 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.deletePad = async function(padID) {
|
||||
let pad = await getPadSafe(padID, true);
|
||||
exports.deletePad = async function (padID) {
|
||||
const pad = await getPadSafe(padID, true);
|
||||
await pad.remove();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
restoreRevision(padID, [rev]) Restores revision from past as new changeset
|
||||
|
@ -503,34 +501,34 @@ exports.deletePad = async function(padID) {
|
|||
{code:0, message:"ok", data:null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.restoreRevision = async function(padID, rev) {
|
||||
exports.restoreRevision = async function (padID, rev) {
|
||||
// check if rev is a number
|
||||
if (rev === undefined) {
|
||||
throw new customError("rev is not defined", "apierror");
|
||||
throw new customError('rev is not defined', 'apierror');
|
||||
}
|
||||
rev = checkValidRev(rev);
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
// check if this is a valid revision
|
||||
if (rev > pad.getHeadRevisionNumber()) {
|
||||
throw new customError("rev is higher than the head revision of the pad", "apierror");
|
||||
throw new customError('rev is higher than the head revision of the pad', 'apierror');
|
||||
}
|
||||
|
||||
let atext = await pad.getInternalRevisionAText(rev);
|
||||
const atext = await pad.getInternalRevisionAText(rev);
|
||||
|
||||
var oldText = pad.text();
|
||||
atext.text += "\n";
|
||||
const oldText = pad.text();
|
||||
atext.text += '\n';
|
||||
|
||||
function eachAttribRun(attribs, func) {
|
||||
var attribsIter = Changeset.opIterator(attribs);
|
||||
var textIndex = 0;
|
||||
var newTextStart = 0;
|
||||
var newTextEnd = atext.text.length;
|
||||
const attribsIter = Changeset.opIterator(attribs);
|
||||
let textIndex = 0;
|
||||
const newTextStart = 0;
|
||||
const newTextEnd = atext.text.length;
|
||||
while (attribsIter.hasNext()) {
|
||||
var op = attribsIter.next();
|
||||
var nextIndex = textIndex + op.chars;
|
||||
const op = attribsIter.next();
|
||||
const nextIndex = textIndex + op.chars;
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
|
||||
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
|
||||
}
|
||||
|
@ -539,14 +537,14 @@ exports.restoreRevision = async function(padID, rev) {
|
|||
}
|
||||
|
||||
// create a new changeset with a helper builder object
|
||||
var builder = Changeset.builder(oldText.length);
|
||||
const builder = Changeset.builder(oldText.length);
|
||||
|
||||
// assemble each line into the builder
|
||||
eachAttribRun(atext.attribs, function(start, end, attribs) {
|
||||
eachAttribRun(atext.attribs, (start, end, attribs) => {
|
||||
builder.insert(atext.text.substring(start, end), attribs);
|
||||
});
|
||||
|
||||
var lastNewlinePos = oldText.lastIndexOf('\n');
|
||||
const lastNewlinePos = oldText.lastIndexOf('\n');
|
||||
if (lastNewlinePos < 0) {
|
||||
builder.remove(oldText.length - 1, 0);
|
||||
} else {
|
||||
|
@ -554,13 +552,13 @@ exports.restoreRevision = async function(padID, rev) {
|
|||
builder.remove(oldText.length - lastNewlinePos - 1, 0);
|
||||
}
|
||||
|
||||
var changeset = builder.toString();
|
||||
const changeset = builder.toString();
|
||||
|
||||
await Promise.all([
|
||||
pad.appendRevision(changeset),
|
||||
padMessageHandler.updatePadClients(pad),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true,
|
||||
|
@ -571,10 +569,10 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {padID: destinationID}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.copyPad = async function(sourceID, destinationID, force) {
|
||||
let pad = await getPadSafe(sourceID, true);
|
||||
exports.copyPad = async function (sourceID, destinationID, force) {
|
||||
const pad = await getPadSafe(sourceID, true);
|
||||
await pad.copy(destinationID, force);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
copyPadWithoutHistory(sourceID, destinationID[, force=false]) copies a pad. If force is true,
|
||||
|
@ -585,10 +583,10 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {padID: destinationID}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.copyPadWithoutHistory = async function(sourceID, destinationID, force) {
|
||||
let pad = await getPadSafe(sourceID, true);
|
||||
exports.copyPadWithoutHistory = async function (sourceID, destinationID, force) {
|
||||
const pad = await getPadSafe(sourceID, true);
|
||||
await pad.copyPadWithoutHistory(destinationID, force);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
movePad(sourceID, destinationID[, force=false]) moves a pad. If force is true,
|
||||
|
@ -599,11 +597,11 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {padID: destinationID}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.movePad = async function(sourceID, destinationID, force) {
|
||||
let pad = await getPadSafe(sourceID, true);
|
||||
exports.movePad = async function (sourceID, destinationID, force) {
|
||||
const pad = await getPadSafe(sourceID, true);
|
||||
await pad.copy(destinationID, force);
|
||||
await pad.remove();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getReadOnlyLink(padID) returns the read only link of a pad
|
||||
|
@ -613,15 +611,15 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getReadOnlyID = async function(padID) {
|
||||
exports.getReadOnlyID = async function (padID) {
|
||||
// we don't need the pad object, but this function does all the security stuff for us
|
||||
await getPadSafe(padID, true);
|
||||
|
||||
// get the readonlyId
|
||||
let readOnlyID = await readOnlyManager.getReadOnlyId(padID);
|
||||
const readOnlyID = await readOnlyManager.getReadOnlyId(padID);
|
||||
|
||||
return { readOnlyID };
|
||||
}
|
||||
return {readOnlyID};
|
||||
};
|
||||
|
||||
/**
|
||||
getPadID(roID) returns the padID of a pad based on the readonlyID(roID)
|
||||
|
@ -631,15 +629,15 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {padID: padID}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getPadID = async function(roID) {
|
||||
exports.getPadID = async function (roID) {
|
||||
// get the PadId
|
||||
let padID = await readOnlyManager.getPadId(roID);
|
||||
const padID = await readOnlyManager.getPadId(roID);
|
||||
if (padID === null) {
|
||||
throw new customError("padID does not exist", "apierror");
|
||||
throw new customError('padID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
return { padID };
|
||||
}
|
||||
return {padID};
|
||||
};
|
||||
|
||||
/**
|
||||
setPublicStatus(padID, publicStatus) sets a boolean for the public status of a pad
|
||||
|
@ -649,20 +647,20 @@ Example returns:
|
|||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.setPublicStatus = async function(padID, publicStatus) {
|
||||
exports.setPublicStatus = async function (padID, publicStatus) {
|
||||
// ensure this is a group pad
|
||||
checkGroupPad(padID, "publicStatus");
|
||||
checkGroupPad(padID, 'publicStatus');
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
|
||||
// convert string to boolean
|
||||
if (typeof publicStatus === "string") {
|
||||
publicStatus = (publicStatus.toLowerCase() === "true");
|
||||
if (typeof publicStatus === 'string') {
|
||||
publicStatus = (publicStatus.toLowerCase() === 'true');
|
||||
}
|
||||
|
||||
await pad.setPublicStatus(publicStatus);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getPublicStatus(padID) return true of false
|
||||
|
@ -672,14 +670,14 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {publicStatus: true}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getPublicStatus = async function(padID) {
|
||||
exports.getPublicStatus = async function (padID) {
|
||||
// ensure this is a group pad
|
||||
checkGroupPad(padID, "publicStatus");
|
||||
checkGroupPad(padID, 'publicStatus');
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { publicStatus: pad.getPublicStatus() };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {publicStatus: pad.getPublicStatus()};
|
||||
};
|
||||
|
||||
/**
|
||||
listAuthorsOfPad(padID) returns an array of authors who contributed to this pad
|
||||
|
@ -689,12 +687,12 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.listAuthorsOfPad = async function(padID) {
|
||||
exports.listAuthorsOfPad = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
let authorIDs = pad.getAllAuthors();
|
||||
return { authorIDs };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
const authorIDs = pad.getAllAuthors();
|
||||
return {authorIDs};
|
||||
};
|
||||
|
||||
/**
|
||||
sendClientsMessage(padID, msg) sends a message to all clients connected to the
|
||||
|
@ -719,10 +717,10 @@ Example returns:
|
|||
{code: 1, message:"padID does not exist"}
|
||||
*/
|
||||
|
||||
exports.sendClientsMessage = async function(padID, msg) {
|
||||
let pad = await getPadSafe(padID, true);
|
||||
exports.sendClientsMessage = async function (padID, msg) {
|
||||
const pad = await getPadSafe(padID, true);
|
||||
padMessageHandler.handleCustomMessage(padID, msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
checkToken() returns ok when the current api token is valid
|
||||
|
@ -732,8 +730,8 @@ Example returns:
|
|||
{"code":0,"message":"ok","data":null}
|
||||
{"code":4,"message":"no or wrong API Key","data":null}
|
||||
*/
|
||||
exports.checkToken = async function() {
|
||||
}
|
||||
exports.checkToken = async function () {
|
||||
};
|
||||
|
||||
/**
|
||||
getChatHead(padID) returns the chatHead (last number of the last chat-message) of the pad
|
||||
|
@ -743,11 +741,11 @@ Example returns:
|
|||
{code: 0, message:"ok", data: {chatHead: 42}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getChatHead = async function(padID) {
|
||||
exports.getChatHead = async function (padID) {
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
return { chatHead: pad.chatHead };
|
||||
}
|
||||
const pad = await getPadSafe(padID, true);
|
||||
return {chatHead: pad.chatHead};
|
||||
};
|
||||
|
||||
/**
|
||||
createDiffHTML(padID, startRev, endRev) returns an object of diffs from 2 points in a pad
|
||||
|
@ -757,8 +755,7 @@ Example returns:
|
|||
{"code":0,"message":"ok","data":{"html":"<style>\n.authora_HKIv23mEbachFYfH {background-color: #a979d9}\n.authora_n4gEeMLsv1GivNeh {background-color: #a9b5d9}\n.removed {text-decoration: line-through; -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)'; filter: alpha(opacity=80); opacity: 0.8; }\n</style>Welcome to Etherpad!<br><br>This pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!<br><br>Get involved with Etherpad at <a href=\"http://etherpad.org\">http://etherpad.org</a><br><span class=\"authora_HKIv23mEbachFYfH\">aw</span><br><br>","authors":["a.HKIv23mEbachFYfH",""]}}
|
||||
{"code":4,"message":"no or wrong API Key","data":null}
|
||||
*/
|
||||
exports.createDiffHTML = async function(padID, startRev, endRev) {
|
||||
|
||||
exports.createDiffHTML = async function (padID, startRev, endRev) {
|
||||
// check if startRev is a number
|
||||
if (startRev !== undefined) {
|
||||
startRev = checkValidRev(startRev);
|
||||
|
@ -770,18 +767,18 @@ exports.createDiffHTML = async function(padID, startRev, endRev) {
|
|||
}
|
||||
|
||||
// get the pad
|
||||
let pad = await getPadSafe(padID, true);
|
||||
const pad = await getPadSafe(padID, true);
|
||||
try {
|
||||
var padDiff = new PadDiff(pad, startRev, endRev);
|
||||
} catch (e) {
|
||||
throw { stop: e.message };
|
||||
throw {stop: e.message};
|
||||
}
|
||||
|
||||
let html = await padDiff.getHtml();
|
||||
let authors = await padDiff.getAuthors();
|
||||
const html = await padDiff.getHtml();
|
||||
const authors = await padDiff.getAuthors();
|
||||
|
||||
return { html, authors };
|
||||
}
|
||||
return {html, authors};
|
||||
};
|
||||
|
||||
/* ********************
|
||||
** GLOBAL FUNCTIONS **
|
||||
|
@ -796,20 +793,20 @@ exports.createDiffHTML = async function(padID, startRev, endRev) {
|
|||
{"code":4,"message":"no or wrong API Key","data":null}
|
||||
*/
|
||||
|
||||
exports.getStats = async function() {
|
||||
exports.getStats = async function () {
|
||||
const sessionInfos = padMessageHandler.sessioninfos;
|
||||
|
||||
const sessionKeys = Object.keys(sessionInfos);
|
||||
const activePads = new Set(Object.entries(sessionInfos).map(k => k[1].padId));
|
||||
const activePads = new Set(Object.entries(sessionInfos).map((k) => k[1].padId));
|
||||
|
||||
const { padIDs } = await padManager.listAllPads();
|
||||
const {padIDs} = await padManager.listAllPads();
|
||||
|
||||
return {
|
||||
totalPads: padIDs.length,
|
||||
totalSessions: sessionKeys.length,
|
||||
totalActivePads: activePads.size,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/* ****************************
|
||||
** INTERNAL HELPER FUNCTIONS *
|
||||
|
@ -817,32 +814,32 @@ exports.getStats = async function() {
|
|||
|
||||
// checks if a number is an int
|
||||
function is_int(value) {
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value)
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
|
||||
}
|
||||
|
||||
// gets a pad safe
|
||||
async function getPadSafe(padID, shouldExist, text) {
|
||||
// check if padID is a string
|
||||
if (typeof padID !== "string") {
|
||||
throw new customError("padID is not a string", "apierror");
|
||||
if (typeof padID !== 'string') {
|
||||
throw new customError('padID is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// check if the padID maches the requirements
|
||||
if (!padManager.isValidPadId(padID)) {
|
||||
throw new customError("padID did not match requirements", "apierror");
|
||||
throw new customError('padID did not match requirements', 'apierror');
|
||||
}
|
||||
|
||||
// check if the pad exists
|
||||
let exists = await padManager.doesPadExists(padID);
|
||||
const exists = await padManager.doesPadExists(padID);
|
||||
|
||||
if (!exists && shouldExist) {
|
||||
// does not exist, but should
|
||||
throw new customError("padID does not exist", "apierror");
|
||||
throw new customError('padID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
if (exists && !shouldExist) {
|
||||
// does exist, but shouldn't
|
||||
throw new customError("padID does already exist", "apierror");
|
||||
throw new customError('padID does already exist', 'apierror');
|
||||
}
|
||||
|
||||
// pad exists, let's get it
|
||||
|
@ -852,23 +849,23 @@ async function getPadSafe(padID, shouldExist, text) {
|
|||
// checks if a rev is a legal number
|
||||
// pre-condition is that `rev` is not undefined
|
||||
function checkValidRev(rev) {
|
||||
if (typeof rev !== "number") {
|
||||
if (typeof rev !== 'number') {
|
||||
rev = parseInt(rev, 10);
|
||||
}
|
||||
|
||||
// check if rev is a number
|
||||
if (isNaN(rev)) {
|
||||
throw new customError("rev is not a number", "apierror");
|
||||
throw new customError('rev is not a number', 'apierror');
|
||||
}
|
||||
|
||||
// ensure this is not a negative number
|
||||
if (rev < 0) {
|
||||
throw new customError("rev is not a negative number", "apierror");
|
||||
throw new customError('rev is not a negative number', 'apierror');
|
||||
}
|
||||
|
||||
// ensure this is not a float value
|
||||
if (!is_int(rev)) {
|
||||
throw new customError("rev is a float value", "apierror");
|
||||
throw new customError('rev is a float value', 'apierror');
|
||||
}
|
||||
|
||||
return rev;
|
||||
|
@ -877,7 +874,7 @@ function checkValidRev(rev) {
|
|||
// checks if a padID is part of a group
|
||||
function checkGroupPad(padID, field) {
|
||||
// ensure this is a group pad
|
||||
if (padID && padID.indexOf("$") === -1) {
|
||||
throw new customError(`You can only get/set the ${field} of pads that belong to a group`, "apierror");
|
||||
if (padID && padID.indexOf('$') === -1) {
|
||||
throw new customError(`You can only get/set the ${field} of pads that belong to a group`, 'apierror');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,31 +18,87 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var db = require("./DB");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
const db = require('./DB');
|
||||
const customError = require('../utils/customError');
|
||||
const 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"
|
||||
'#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
|
||||
*/
|
||||
exports.doesAuthorExist = async function(authorID) {
|
||||
let author = await db.get("globalAuthor:" + authorID);
|
||||
exports.doesAuthorExist = async function (authorID) {
|
||||
const author = await db.get(`globalAuthor:${authorID}`);
|
||||
|
||||
return author !== null;
|
||||
}
|
||||
};
|
||||
|
||||
/* exported for backwards compatibility */
|
||||
exports.doesAuthorExists = exports.doesAuthorExist;
|
||||
|
@ -51,20 +107,20 @@ exports.doesAuthorExists = exports.doesAuthorExist;
|
|||
* Returns the AuthorID for a token.
|
||||
* @param {String} token The token
|
||||
*/
|
||||
exports.getAuthor4Token = async function(token) {
|
||||
let author = await mapAuthorWithDBKey("token2author", token);
|
||||
exports.getAuthor4Token = async function (token) {
|
||||
const author = await mapAuthorWithDBKey('token2author', token);
|
||||
|
||||
// return only the sub value authorID
|
||||
return author ? author.authorID : author;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a mapper.
|
||||
* @param {String} token The mapper
|
||||
* @param {String} name The name of the author (optional)
|
||||
*/
|
||||
exports.createAuthorIfNotExistsFor = async function(authorMapper, name) {
|
||||
let author = await mapAuthorWithDBKey("mapper2author", authorMapper);
|
||||
exports.createAuthorIfNotExistsFor = async function (authorMapper, name) {
|
||||
const author = await mapAuthorWithDBKey('mapper2author', authorMapper);
|
||||
|
||||
if (name) {
|
||||
// set the name of this author
|
||||
|
@ -80,16 +136,16 @@ exports.createAuthorIfNotExistsFor = async function(authorMapper, name) {
|
|||
* @param {String} mapperkey The database key name for this mapper
|
||||
* @param {String} mapper The mapper
|
||||
*/
|
||||
async function mapAuthorWithDBKey (mapperkey, mapper) {
|
||||
async function mapAuthorWithDBKey(mapperkey, mapper) {
|
||||
// try to map to an author
|
||||
let author = await db.get(mapperkey + ":" + mapper);
|
||||
const author = await db.get(`${mapperkey}:${mapper}`);
|
||||
|
||||
if (author === null) {
|
||||
// there is no author with this mapper, so create one
|
||||
let author = await exports.createAuthor(null);
|
||||
const author = await exports.createAuthor(null);
|
||||
|
||||
// create the token2author relation
|
||||
await db.set(mapperkey + ":" + mapper, author.authorID);
|
||||
await db.set(`${mapperkey}:${mapper}`, author.authorID);
|
||||
|
||||
// return the author
|
||||
return author;
|
||||
|
@ -97,109 +153,109 @@ async function mapAuthorWithDBKey (mapperkey, mapper) {
|
|||
|
||||
// there is an author with this mapper
|
||||
// update the timestamp of this author
|
||||
await db.setSub("globalAuthor:" + author, ["timestamp"], Date.now());
|
||||
await db.setSub(`globalAuthor:${author}`, ['timestamp'], Date.now());
|
||||
|
||||
// return the author
|
||||
return { authorID: author};
|
||||
return {authorID: author};
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function that creates the database entry for an author
|
||||
* @param {String} name The name of the author
|
||||
*/
|
||||
exports.createAuthor = function(name) {
|
||||
exports.createAuthor = function (name) {
|
||||
// create the new author name
|
||||
let author = "a." + randomString(16);
|
||||
const author = `a.${randomString(16)}`;
|
||||
|
||||
// create the globalAuthors db entry
|
||||
let authorObj = {
|
||||
"colorId": Math.floor(Math.random() * (exports.getColorPalette().length)),
|
||||
"name": name,
|
||||
"timestamp": Date.now()
|
||||
const authorObj = {
|
||||
colorId: Math.floor(Math.random() * (exports.getColorPalette().length)),
|
||||
name,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
// set the global author db entry
|
||||
// NB: no await, since we're not waiting for the DB set to finish
|
||||
db.set("globalAuthor:" + author, authorObj);
|
||||
db.set(`globalAuthor:${author}`, authorObj);
|
||||
|
||||
return { authorID: author };
|
||||
}
|
||||
return {authorID: author};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the Author Obj of the author
|
||||
* @param {String} author The id of the author
|
||||
*/
|
||||
exports.getAuthor = function(author) {
|
||||
exports.getAuthor = function (author) {
|
||||
// NB: result is already a Promise
|
||||
return db.get("globalAuthor:" + author);
|
||||
}
|
||||
return db.get(`globalAuthor:${author}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the color Id of the author
|
||||
* @param {String} author The id of the author
|
||||
*/
|
||||
exports.getAuthorColorId = function(author) {
|
||||
return db.getSub("globalAuthor:" + author, ["colorId"]);
|
||||
}
|
||||
exports.getAuthorColorId = function (author) {
|
||||
return db.getSub(`globalAuthor:${author}`, ['colorId']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the color Id of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {String} colorId The color id of the author
|
||||
*/
|
||||
exports.setAuthorColorId = function(author, colorId) {
|
||||
return db.setSub("globalAuthor:" + author, ["colorId"], colorId);
|
||||
}
|
||||
exports.setAuthorColorId = function (author, colorId) {
|
||||
return db.setSub(`globalAuthor:${author}`, ['colorId'], colorId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the author
|
||||
* @param {String} author The id of the author
|
||||
*/
|
||||
exports.getAuthorName = function(author) {
|
||||
return db.getSub("globalAuthor:" + author, ["name"]);
|
||||
}
|
||||
exports.getAuthorName = function (author) {
|
||||
return db.getSub(`globalAuthor:${author}`, ['name']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the name of the author
|
||||
* @param {String} author The id of the author
|
||||
* @param {String} name The name of the author
|
||||
*/
|
||||
exports.setAuthorName = function(author, name) {
|
||||
return db.setSub("globalAuthor:" + author, ["name"], name);
|
||||
}
|
||||
exports.setAuthorName = function (author, name) {
|
||||
return db.setSub(`globalAuthor:${author}`, ['name'], name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of all pads this author contributed to
|
||||
* @param {String} author The id of the author
|
||||
*/
|
||||
exports.listPadsOfAuthor = async function(authorID) {
|
||||
exports.listPadsOfAuthor = async function (authorID) {
|
||||
/* 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
|
||||
* (2) When a pad is deleted, each author of that pad is also updated
|
||||
*/
|
||||
|
||||
// get the globalAuthor
|
||||
let author = await db.get("globalAuthor:" + authorID);
|
||||
const author = await db.get(`globalAuthor:${authorID}`);
|
||||
|
||||
if (author === null) {
|
||||
// author does not exist
|
||||
throw new customError("authorID does not exist", "apierror");
|
||||
throw new customError('authorID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// everything is fine, return the pad IDs
|
||||
let padIDs = Object.keys(author.padIDs || {});
|
||||
const padIDs = Object.keys(author.padIDs || {});
|
||||
|
||||
return { padIDs };
|
||||
}
|
||||
return {padIDs};
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a new pad to the list of contributions
|
||||
* @param {String} author The id of the author
|
||||
* @param {String} padID The id of the pad the author contributes to
|
||||
*/
|
||||
exports.addPad = async function(authorID, padID) {
|
||||
exports.addPad = async function (authorID, padID) {
|
||||
// get the entry
|
||||
let author = await db.get("globalAuthor:" + authorID);
|
||||
const author = await db.get(`globalAuthor:${authorID}`);
|
||||
|
||||
if (author === null) return;
|
||||
|
||||
|
@ -216,22 +272,22 @@ exports.addPad = async function(authorID, padID) {
|
|||
author.padIDs[padID] = 1; // anything, because value is not used
|
||||
|
||||
// save the new element back
|
||||
db.set("globalAuthor:" + authorID, author);
|
||||
}
|
||||
db.set(`globalAuthor:${authorID}`, author);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a pad from the list of contributions
|
||||
* @param {String} author The id of the author
|
||||
* @param {String} padID The id of the pad the author contributes to
|
||||
*/
|
||||
exports.removePad = async function(authorID, padID) {
|
||||
let author = await db.get("globalAuthor:" + authorID);
|
||||
exports.removePad = async function (authorID, padID) {
|
||||
const author = await db.get(`globalAuthor:${authorID}`);
|
||||
|
||||
if (author === null) return;
|
||||
|
||||
if (author.padIDs !== null) {
|
||||
// remove pad from author
|
||||
delete author.padIDs[padID];
|
||||
await db.set('globalAuthor:' + authorID, author);
|
||||
await db.set(`globalAuthor:${authorID}`, author);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var ueberDB = require("ueberdb2");
|
||||
var settings = require("../utils/Settings");
|
||||
var log4js = require('log4js');
|
||||
const util = require("util");
|
||||
const ueberDB = require('ueberdb2');
|
||||
const settings = require('../utils/Settings');
|
||||
const log4js = require('log4js');
|
||||
const util = require('util');
|
||||
|
||||
// set database settings
|
||||
let db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger("ueberDB"));
|
||||
const db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger('ueberDB'));
|
||||
|
||||
/**
|
||||
* The UeberDB Object that provides the database functions
|
||||
|
@ -36,32 +36,32 @@ exports.db = null;
|
|||
* Initalizes the database with the settings provided by the settings module
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.init = function() {
|
||||
exports.init = function () {
|
||||
// initalize the database async
|
||||
return new Promise((resolve, reject) => {
|
||||
db.init(function(err) {
|
||||
db.init((err) => {
|
||||
if (err) {
|
||||
// there was an error while initializing the database, output it and stop
|
||||
console.error("ERROR: Problem while initalizing the database");
|
||||
console.error('ERROR: Problem while initalizing the database');
|
||||
console.error(err.stack ? err.stack : err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// everything ok, set up Promise-based methods
|
||||
['get', 'set', 'findKeys', 'getSub', 'setSub', 'remove', 'doShutdown'].forEach(fn => {
|
||||
['get', 'set', 'findKeys', 'getSub', 'setSub', 'remove', 'doShutdown'].forEach((fn) => {
|
||||
exports[fn] = util.promisify(db[fn].bind(db));
|
||||
});
|
||||
|
||||
// set up wrappers for get and getSub that can't return "undefined"
|
||||
let get = exports.get;
|
||||
exports.get = async function(key) {
|
||||
let result = await get(key);
|
||||
const get = exports.get;
|
||||
exports.get = async function (key) {
|
||||
const result = await get(key);
|
||||
return (result === undefined) ? null : result;
|
||||
};
|
||||
|
||||
let getSub = exports.getSub;
|
||||
exports.getSub = async function(key, sub) {
|
||||
let result = await getSub(key, sub);
|
||||
const getSub = exports.getSub;
|
||||
exports.getSub = async function (key, sub) {
|
||||
const result = await getSub(key, sub);
|
||||
return (result === undefined) ? null : result;
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,7 @@ exports.init = function() {
|
|||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.shutdown = async (hookName, context) => {
|
||||
await exports.doShutdown();
|
||||
|
|
|
@ -18,52 +18,48 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
var db = require("./DB");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
const customError = require('../utils/customError');
|
||||
const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
const db = require('./DB');
|
||||
const padManager = require('./PadManager');
|
||||
const sessionManager = require('./SessionManager');
|
||||
|
||||
exports.listAllGroups = async function() {
|
||||
let groups = await db.get("groups");
|
||||
exports.listAllGroups = async function () {
|
||||
let groups = await db.get('groups');
|
||||
groups = groups || {};
|
||||
|
||||
let groupIDs = Object.keys(groups);
|
||||
return { groupIDs };
|
||||
}
|
||||
const groupIDs = Object.keys(groups);
|
||||
return {groupIDs};
|
||||
};
|
||||
|
||||
exports.deleteGroup = async function(groupID) {
|
||||
let group = await db.get("group:" + groupID);
|
||||
exports.deleteGroup = async function (groupID) {
|
||||
const group = await db.get(`group:${groupID}`);
|
||||
|
||||
// ensure group exists
|
||||
if (group == null) {
|
||||
// group does not exist
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
throw new customError('groupID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// iterate through all pads of this group and delete them (in parallel)
|
||||
await Promise.all(Object.keys(group.pads).map(padID => {
|
||||
return padManager.getPad(padID).then(pad => pad.remove());
|
||||
}));
|
||||
await Promise.all(Object.keys(group.pads).map((padID) => padManager.getPad(padID).then((pad) => pad.remove())));
|
||||
|
||||
// iterate through group2sessions and delete all sessions
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
let sessions = group2sessions ? group2sessions.sessionIDs : {};
|
||||
const group2sessions = await db.get(`group2sessions:${groupID}`);
|
||||
const sessions = group2sessions ? group2sessions.sessionIDs : {};
|
||||
|
||||
// loop through all sessions and delete them (in parallel)
|
||||
await Promise.all(Object.keys(sessions).map(session => {
|
||||
return sessionManager.deleteSession(session);
|
||||
}));
|
||||
await Promise.all(Object.keys(sessions).map((session) => sessionManager.deleteSession(session)));
|
||||
|
||||
// remove group and group2sessions entry
|
||||
await db.remove("group2sessions:" + groupID);
|
||||
await db.remove("group:" + groupID);
|
||||
await db.remove(`group2sessions:${groupID}`);
|
||||
await db.remove(`group:${groupID}`);
|
||||
|
||||
// unlist the group
|
||||
let groups = await exports.listAllGroups();
|
||||
groups = groups ? groups.groupIDs : [];
|
||||
|
||||
let index = groups.indexOf(groupID);
|
||||
const index = groups.indexOf(groupID);
|
||||
|
||||
if (index === -1) {
|
||||
// it's not listed
|
||||
|
@ -75,102 +71,102 @@ exports.deleteGroup = async function(groupID) {
|
|||
groups.splice(index, 1);
|
||||
|
||||
// regenerate group list
|
||||
var newGroups = {};
|
||||
groups.forEach(group => newGroups[group] = 1);
|
||||
await db.set("groups", newGroups);
|
||||
}
|
||||
const newGroups = {};
|
||||
groups.forEach((group) => newGroups[group] = 1);
|
||||
await db.set('groups', newGroups);
|
||||
};
|
||||
|
||||
exports.doesGroupExist = async function(groupID) {
|
||||
exports.doesGroupExist = async function (groupID) {
|
||||
// try to get the group entry
|
||||
let group = await db.get("group:" + groupID);
|
||||
const group = await db.get(`group:${groupID}`);
|
||||
|
||||
return (group != null);
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroup = async function() {
|
||||
exports.createGroup = async function () {
|
||||
// search for non existing groupID
|
||||
var groupID = "g." + randomString(16);
|
||||
const groupID = `g.${randomString(16)}`;
|
||||
|
||||
// create the group
|
||||
await db.set("group:" + groupID, {pads: {}});
|
||||
await db.set(`group:${groupID}`, {pads: {}});
|
||||
|
||||
// list the group
|
||||
let groups = await exports.listAllGroups();
|
||||
groups = groups? groups.groupIDs : [];
|
||||
groups = groups ? groups.groupIDs : [];
|
||||
groups.push(groupID);
|
||||
|
||||
// regenerate group list
|
||||
var newGroups = {};
|
||||
groups.forEach(group => newGroups[group] = 1);
|
||||
await db.set("groups", newGroups);
|
||||
const newGroups = {};
|
||||
groups.forEach((group) => newGroups[group] = 1);
|
||||
await db.set('groups', newGroups);
|
||||
|
||||
return { groupID };
|
||||
}
|
||||
return {groupID};
|
||||
};
|
||||
|
||||
exports.createGroupIfNotExistsFor = async function(groupMapper) {
|
||||
exports.createGroupIfNotExistsFor = async function (groupMapper) {
|
||||
// ensure mapper is optional
|
||||
if (typeof groupMapper !== "string") {
|
||||
throw new customError("groupMapper is not a string", "apierror");
|
||||
if (typeof groupMapper !== 'string') {
|
||||
throw new customError('groupMapper is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// try to get a group for this mapper
|
||||
let groupID = await db.get("mapper2group:" + groupMapper);
|
||||
const groupID = await db.get(`mapper2group:${groupMapper}`);
|
||||
|
||||
if (groupID) {
|
||||
// there is a group for this mapper
|
||||
let exists = await exports.doesGroupExist(groupID);
|
||||
const exists = await exports.doesGroupExist(groupID);
|
||||
|
||||
if (exists) return { groupID };
|
||||
if (exists) return {groupID};
|
||||
}
|
||||
|
||||
// hah, the returned group doesn't exist, let's create one
|
||||
let result = await exports.createGroup();
|
||||
const result = await exports.createGroup();
|
||||
|
||||
// create the mapper entry for this group
|
||||
await db.set("mapper2group:" + groupMapper, result.groupID);
|
||||
await db.set(`mapper2group:${groupMapper}`, result.groupID);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroupPad = async function(groupID, padName, text) {
|
||||
exports.createGroupPad = async function (groupID, padName, text) {
|
||||
// create the padID
|
||||
let padID = groupID + "$" + padName;
|
||||
const padID = `${groupID}$${padName}`;
|
||||
|
||||
// ensure group exists
|
||||
let groupExists = await exports.doesGroupExist(groupID);
|
||||
const groupExists = await exports.doesGroupExist(groupID);
|
||||
|
||||
if (!groupExists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
throw new customError('groupID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// ensure pad doesn't exist already
|
||||
let padExists = await padManager.doesPadExists(padID);
|
||||
const padExists = await padManager.doesPadExists(padID);
|
||||
|
||||
if (padExists) {
|
||||
// pad exists already
|
||||
throw new customError("padName does already exist", "apierror");
|
||||
throw new customError('padName does already exist', 'apierror');
|
||||
}
|
||||
|
||||
// create the pad
|
||||
await padManager.getPad(padID, text);
|
||||
|
||||
//create an entry in the group for this pad
|
||||
await db.setSub("group:" + groupID, ["pads", padID], 1);
|
||||
// create an entry in the group for this pad
|
||||
await db.setSub(`group:${groupID}`, ['pads', padID], 1);
|
||||
|
||||
return { padID };
|
||||
}
|
||||
return {padID};
|
||||
};
|
||||
|
||||
exports.listPads = async function(groupID) {
|
||||
let exists = await exports.doesGroupExist(groupID);
|
||||
exports.listPads = async function (groupID) {
|
||||
const exists = await exports.doesGroupExist(groupID);
|
||||
|
||||
// ensure the group exists
|
||||
if (!exists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
throw new customError('groupID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// group exists, let's get the pads
|
||||
let result = await db.getSub("group:" + groupID, ["pads"]);
|
||||
let padIDs = Object.keys(result);
|
||||
const result = await db.getSub(`group:${groupID}`, ['pads']);
|
||||
const padIDs = Object.keys(result);
|
||||
|
||||
return { padIDs };
|
||||
}
|
||||
return {padIDs};
|
||||
};
|
||||
|
|
|
@ -3,36 +3,36 @@
|
|||
*/
|
||||
|
||||
|
||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
||||
var db = require("./DB");
|
||||
var settings = require('../utils/Settings');
|
||||
var authorManager = require("./AuthorManager");
|
||||
var padManager = require("./PadManager");
|
||||
var padMessageHandler = require("../handler/PadMessageHandler");
|
||||
var groupManager = require("./GroupManager");
|
||||
var customError = require("../utils/customError");
|
||||
var readOnlyManager = require("./ReadOnlyManager");
|
||||
var crypto = require("crypto");
|
||||
var randomString = require("../utils/randomstring");
|
||||
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||
var promises = require('../utils/promises')
|
||||
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||
const AttributePool = require('ep_etherpad-lite/static/js/AttributePool');
|
||||
const db = require('./DB');
|
||||
const settings = require('../utils/Settings');
|
||||
const authorManager = require('./AuthorManager');
|
||||
const padManager = require('./PadManager');
|
||||
const padMessageHandler = require('../handler/PadMessageHandler');
|
||||
const groupManager = require('./GroupManager');
|
||||
const customError = require('../utils/customError');
|
||||
const readOnlyManager = require('./ReadOnlyManager');
|
||||
const crypto = require('crypto');
|
||||
const randomString = require('../utils/randomstring');
|
||||
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||
const promises = require('../utils/promises');
|
||||
|
||||
// serialization/deserialization attributes
|
||||
var attributeBlackList = ["id"];
|
||||
var jsonableList = ["pool"];
|
||||
const attributeBlackList = ['id'];
|
||||
const jsonableList = ['pool'];
|
||||
|
||||
/**
|
||||
* 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, ' ');
|
||||
return txt.replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
|
||||
};
|
||||
|
||||
|
||||
let Pad = function Pad(id) {
|
||||
this.atext = Changeset.makeAText("\n");
|
||||
const Pad = function Pad(id) {
|
||||
this.atext = Changeset.makeAText('\n');
|
||||
this.pool = new AttributePool();
|
||||
this.head = -1;
|
||||
this.chatHead = -1;
|
||||
|
@ -56,13 +56,11 @@ Pad.prototype.getSavedRevisionsNumber = function getSavedRevisionsNumber() {
|
|||
};
|
||||
|
||||
Pad.prototype.getSavedRevisionsList = function getSavedRevisionsList() {
|
||||
var savedRev = new Array();
|
||||
for (var rev in this.savedRevisions) {
|
||||
const savedRev = new Array();
|
||||
for (const rev in this.savedRevisions) {
|
||||
savedRev.push(this.savedRevisions[rev].revNum);
|
||||
}
|
||||
savedRev.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
savedRev.sort((a, b) => a - b);
|
||||
return savedRev;
|
||||
};
|
||||
|
||||
|
@ -75,12 +73,12 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author)
|
|||
author = '';
|
||||
}
|
||||
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
const newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
||||
var newRev = ++this.head;
|
||||
const newRev = ++this.head;
|
||||
|
||||
var newRevData = {};
|
||||
const newRevData = {};
|
||||
newRevData.changeset = aChangeset;
|
||||
newRevData.meta = {};
|
||||
newRevData.meta.author = author;
|
||||
|
@ -97,7 +95,7 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author)
|
|||
}
|
||||
|
||||
const p = [
|
||||
db.set('pad:' + this.id + ':revs:' + newRev, newRevData),
|
||||
db.set(`pad:${this.id}:revs:${newRev}`, newRevData),
|
||||
this.saveToDatabase(),
|
||||
];
|
||||
|
||||
|
@ -107,9 +105,9 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author)
|
|||
}
|
||||
|
||||
if (this.head == 0) {
|
||||
hooks.callAll("padCreate", {'pad':this, 'author': author});
|
||||
hooks.callAll('padCreate', {pad: this, author});
|
||||
} else {
|
||||
hooks.callAll("padUpdate", {'pad':this, 'author': author, 'revs': newRev, 'changeset': aChangeset});
|
||||
hooks.callAll('padUpdate', {pad: this, author, revs: newRev, changeset: aChangeset});
|
||||
}
|
||||
|
||||
await Promise.all(p);
|
||||
|
@ -117,10 +115,10 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author)
|
|||
|
||||
// save all attributes to the database
|
||||
Pad.prototype.saveToDatabase = async function saveToDatabase() {
|
||||
var dbObject = {};
|
||||
const dbObject = {};
|
||||
|
||||
for (var attr in this) {
|
||||
if (typeof this[attr] === "function") continue;
|
||||
for (const attr in this) {
|
||||
if (typeof this[attr] === 'function') continue;
|
||||
if (attributeBlackList.indexOf(attr) !== -1) continue;
|
||||
|
||||
dbObject[attr] = this[attr];
|
||||
|
@ -130,32 +128,32 @@ Pad.prototype.saveToDatabase = async function saveToDatabase() {
|
|||
}
|
||||
}
|
||||
|
||||
await db.set('pad:' + this.id, dbObject);
|
||||
}
|
||||
await db.set(`pad:${this.id}`, dbObject);
|
||||
};
|
||||
|
||||
// get time of last edit (changeset application)
|
||||
Pad.prototype.getLastEdit = function getLastEdit() {
|
||||
var revNum = this.getHeadRevisionNumber();
|
||||
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"]);
|
||||
}
|
||||
const revNum = this.getHeadRevisionNumber();
|
||||
return db.getSub(`pad:${this.id}:revs:${revNum}`, ['meta', 'timestamp']);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum) {
|
||||
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["changeset"]);
|
||||
}
|
||||
return db.getSub(`pad:${this.id}:revs:${revNum}`, ['changeset']);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum) {
|
||||
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "author"]);
|
||||
}
|
||||
return db.getSub(`pad:${this.id}:revs:${revNum}`, ['meta', 'author']);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionDate = function getRevisionDate(revNum) {
|
||||
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"]);
|
||||
}
|
||||
return db.getSub(`pad:${this.id}:revs:${revNum}`, ['meta', 'timestamp']);
|
||||
};
|
||||
|
||||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||
var authors = [];
|
||||
const authors = [];
|
||||
|
||||
for(var key in this.pool.numToAttrib) {
|
||||
if (this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "") {
|
||||
for (const key in this.pool.numToAttrib) {
|
||||
if (this.pool.numToAttrib[key][0] == 'author' && this.pool.numToAttrib[key][1] != '') {
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
}
|
||||
}
|
||||
|
@ -164,63 +162,59 @@ Pad.prototype.getAllAuthors = function getAllAuthors() {
|
|||
};
|
||||
|
||||
Pad.prototype.getInternalRevisionAText = async function getInternalRevisionAText(targetRev) {
|
||||
let keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
const keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
|
||||
// find out which changesets are needed
|
||||
let neededChangesets = [];
|
||||
for (let curRev = keyRev; curRev < targetRev; ) {
|
||||
const neededChangesets = [];
|
||||
for (let curRev = keyRev; curRev < targetRev;) {
|
||||
neededChangesets.push(++curRev);
|
||||
}
|
||||
|
||||
// get all needed data out of the database
|
||||
|
||||
// start to get the atext of the key revision
|
||||
let p_atext = db.getSub("pad:" + this.id + ":revs:" + keyRev, ["meta", "atext"]);
|
||||
const p_atext = db.getSub(`pad:${this.id}:revs:${keyRev}`, ['meta', 'atext']);
|
||||
|
||||
// get all needed changesets
|
||||
let changesets = [];
|
||||
await Promise.all(neededChangesets.map(item => {
|
||||
return this.getRevisionChangeset(item).then(changeset => {
|
||||
changesets[item] = changeset;
|
||||
});
|
||||
}));
|
||||
const changesets = [];
|
||||
await Promise.all(neededChangesets.map((item) => this.getRevisionChangeset(item).then((changeset) => {
|
||||
changesets[item] = changeset;
|
||||
})));
|
||||
|
||||
// we should have the atext by now
|
||||
let atext = await p_atext;
|
||||
atext = Changeset.cloneAText(atext);
|
||||
|
||||
// apply all changesets to the key changeset
|
||||
let apool = this.apool();
|
||||
for (let curRev = keyRev; curRev < targetRev; ) {
|
||||
let cs = changesets[++curRev];
|
||||
const apool = this.apool();
|
||||
for (let curRev = keyRev; curRev < targetRev;) {
|
||||
const cs = changesets[++curRev];
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
|
||||
return atext;
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.getRevision = function getRevisionChangeset(revNum) {
|
||||
return db.get("pad:" + this.id + ":revs:" + revNum);
|
||||
}
|
||||
return db.get(`pad:${this.id}:revs:${revNum}`);
|
||||
};
|
||||
|
||||
Pad.prototype.getAllAuthorColors = async function getAllAuthorColors() {
|
||||
let authors = this.getAllAuthors();
|
||||
let returnTable = {};
|
||||
let colorPalette = authorManager.getColorPalette();
|
||||
const authors = this.getAllAuthors();
|
||||
const returnTable = {};
|
||||
const colorPalette = authorManager.getColorPalette();
|
||||
|
||||
await Promise.all(authors.map(author => {
|
||||
return authorManager.getAuthorColorId(author).then(colorId => {
|
||||
// colorId might be a hex color or an number out of the palette
|
||||
returnTable[author] = colorPalette[colorId] || colorId;
|
||||
});
|
||||
}));
|
||||
await Promise.all(authors.map((author) => authorManager.getAuthorColorId(author).then((colorId) => {
|
||||
// colorId might be a hex color or an number out of the palette
|
||||
returnTable[author] = colorPalette[colorId] || colorId;
|
||||
})));
|
||||
|
||||
return returnTable;
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, endRev) {
|
||||
startRev = parseInt(startRev, 10);
|
||||
var head = this.getHeadRevisionNumber();
|
||||
const head = this.getHeadRevisionNumber();
|
||||
endRev = endRev ? parseInt(endRev, 10) : head;
|
||||
|
||||
if (isNaN(startRev) || startRev < 0 || startRev > head) {
|
||||
|
@ -234,7 +228,7 @@ Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, e
|
|||
}
|
||||
|
||||
if (startRev !== null && endRev !== null) {
|
||||
return { startRev: startRev , endRev: endRev }
|
||||
return {startRev, endRev};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@ -251,16 +245,16 @@ Pad.prototype.setText = async function setText(newText) {
|
|||
// clean the new text
|
||||
newText = exports.cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
const oldText = this.text();
|
||||
|
||||
// create the changeset
|
||||
// We want to ensure the pad still ends with a \n, but otherwise keep
|
||||
// getText() and setText() consistent.
|
||||
var changeset;
|
||||
let changeset;
|
||||
if (newText[newText.length - 1] == '\n') {
|
||||
changeset = Changeset.makeSplice(oldText, 0, oldText.length, newText);
|
||||
} else {
|
||||
changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||
changeset = Changeset.makeSplice(oldText, 0, oldText.length - 1, newText);
|
||||
}
|
||||
|
||||
// append the changeset
|
||||
|
@ -271,10 +265,10 @@ Pad.prototype.appendText = async function appendText(newText) {
|
|||
// clean the new text
|
||||
newText = exports.cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
const oldText = this.text();
|
||||
|
||||
// create the changeset
|
||||
var changeset = Changeset.makeSplice(oldText, oldText.length, 0, newText);
|
||||
const changeset = Changeset.makeSplice(oldText, oldText.length, 0, newText);
|
||||
|
||||
// append the changeset
|
||||
await this.appendRevision(changeset);
|
||||
|
@ -284,14 +278,14 @@ Pad.prototype.appendChatMessage = async function appendChatMessage(text, userId,
|
|||
this.chatHead++;
|
||||
// save the chat entry in the database
|
||||
await Promise.all([
|
||||
db.set('pad:' + this.id + ':chat:' + this.chatHead, {text, userId, time}),
|
||||
db.set(`pad:${this.id}:chat:${this.chatHead}`, {text, userId, time}),
|
||||
this.saveToDatabase(),
|
||||
]);
|
||||
};
|
||||
|
||||
Pad.prototype.getChatMessage = async function getChatMessage(entryNum) {
|
||||
// get the chat entry
|
||||
let entry = await db.get("pad:" + this.id + ":chat:" + entryNum);
|
||||
const entry = await db.get(`pad:${this.id}:chat:${entryNum}`);
|
||||
|
||||
// get the authorName if the entry exists
|
||||
if (entry != null) {
|
||||
|
@ -302,49 +296,45 @@ Pad.prototype.getChatMessage = async function getChatMessage(entryNum) {
|
|||
};
|
||||
|
||||
Pad.prototype.getChatMessages = async function getChatMessages(start, end) {
|
||||
|
||||
// collect the numbers of chat entries and in which order we need them
|
||||
let neededEntries = [];
|
||||
const neededEntries = [];
|
||||
for (let order = 0, entryNum = start; entryNum <= end; ++order, ++entryNum) {
|
||||
neededEntries.push({ entryNum, order });
|
||||
neededEntries.push({entryNum, order});
|
||||
}
|
||||
|
||||
// get all entries out of the database
|
||||
let entries = [];
|
||||
await Promise.all(neededEntries.map(entryObject => {
|
||||
return this.getChatMessage(entryObject.entryNum).then(entry => {
|
||||
entries[entryObject.order] = entry;
|
||||
});
|
||||
}));
|
||||
const entries = [];
|
||||
await Promise.all(neededEntries.map((entryObject) => this.getChatMessage(entryObject.entryNum).then((entry) => {
|
||||
entries[entryObject.order] = entry;
|
||||
})));
|
||||
|
||||
// sort out broken chat entries
|
||||
// it looks like in happened in the past that the chat head was
|
||||
// incremented, but the chat message wasn't added
|
||||
let cleanedEntries = entries.filter(entry => {
|
||||
let pass = (entry != null);
|
||||
const cleanedEntries = entries.filter((entry) => {
|
||||
const pass = (entry != null);
|
||||
if (!pass) {
|
||||
console.warn("WARNING: Found broken chat entry in pad " + this.id);
|
||||
console.warn(`WARNING: Found broken chat entry in pad ${this.id}`);
|
||||
}
|
||||
return pass;
|
||||
});
|
||||
|
||||
return cleanedEntries;
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.init = async function init(text) {
|
||||
|
||||
// replace text with default text if text isn't set
|
||||
if (text == null) {
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
// try to load the pad
|
||||
let value = await db.get("pad:" + this.id);
|
||||
const value = await db.get(`pad:${this.id}`);
|
||||
|
||||
// if this pad exists, load it
|
||||
if (value != null) {
|
||||
// copy all attr. To a transfrom via fromJsonable if necassary
|
||||
for (var attr in value) {
|
||||
for (const attr in value) {
|
||||
if (jsonableList.indexOf(attr) !== -1) {
|
||||
this[attr] = this[attr].fromJsonable(value[attr]);
|
||||
} else {
|
||||
|
@ -353,17 +343,17 @@ Pad.prototype.init = async function init(text) {
|
|||
}
|
||||
} else {
|
||||
// this pad doesn't exist, so create it
|
||||
let firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||
const firstChangeset = Changeset.makeSplice('\n', 0, 0, exports.cleanText(text));
|
||||
|
||||
await this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
hooks.callAll("padLoad", { 'pad': this });
|
||||
}
|
||||
hooks.callAll('padLoad', {pad: this});
|
||||
};
|
||||
|
||||
Pad.prototype.copy = async function copy(destinationID, force) {
|
||||
let destGroupID;
|
||||
let sourceID = this.id;
|
||||
const sourceID = this.id;
|
||||
|
||||
// Kick everyone from this pad.
|
||||
// This was commented due to https://github.com/ether/etherpad-lite/issues/3183.
|
||||
|
@ -380,32 +370,28 @@ Pad.prototype.copy = async function copy(destinationID, force) {
|
|||
|
||||
// if force is true and already exists a Pad with the same id, remove that Pad
|
||||
await this.removePadIfForceIsTrueAndAlreadyExist(destinationID, force);
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// copy the 'pad' entry
|
||||
let pad = await db.get("pad:" + sourceID);
|
||||
db.set("pad:" + destinationID, pad);
|
||||
const pad = await db.get(`pad:${sourceID}`);
|
||||
db.set(`pad:${destinationID}`, pad);
|
||||
|
||||
// copy all relations in parallel
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
// copy all chat messages
|
||||
let chatHead = this.chatHead;
|
||||
const chatHead = this.chatHead;
|
||||
for (let i = 0; i <= chatHead; ++i) {
|
||||
let p = db.get("pad:" + sourceID + ":chat:" + i).then(chat => {
|
||||
return db.set("pad:" + destinationID + ":chat:" + i, chat);
|
||||
});
|
||||
const p = db.get(`pad:${sourceID}:chat:${i}`).then((chat) => db.set(`pad:${destinationID}:chat:${i}`, chat));
|
||||
promises.push(p);
|
||||
}
|
||||
|
||||
// copy all revisions
|
||||
let revHead = this.head;
|
||||
const revHead = this.head;
|
||||
for (let i = 0; i <= revHead; ++i) {
|
||||
let p = db.get("pad:" + sourceID + ":revs:" + i).then(rev => {
|
||||
return db.set("pad:" + destinationID + ":revs:" + i, rev);
|
||||
});
|
||||
const p = db.get(`pad:${sourceID}:revs:${i}`).then((rev) => db.set(`pad:${destinationID}:revs:${i}`, rev));
|
||||
promises.push(p);
|
||||
}
|
||||
|
||||
|
@ -416,70 +402,69 @@ Pad.prototype.copy = async function copy(destinationID, force) {
|
|||
|
||||
// Group pad? Add it to the group's list
|
||||
if (destGroupID) {
|
||||
await db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
||||
await db.setSub(`group:${destGroupID}`, ['pads', destinationID], 1);
|
||||
}
|
||||
|
||||
// delay still necessary?
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
// Initialize the new pad (will update the listAllPads cache)
|
||||
await padManager.getPad(destinationID, null); // this runs too early.
|
||||
|
||||
// let the plugins know the pad was copied
|
||||
hooks.callAll('padCopy', { 'originalPad': this, 'destinationID': destinationID });
|
||||
hooks.callAll('padCopy', {originalPad: this, destinationID});
|
||||
|
||||
return { padID: destinationID };
|
||||
}
|
||||
return {padID: destinationID};
|
||||
};
|
||||
|
||||
Pad.prototype.checkIfGroupExistAndReturnIt = async function checkIfGroupExistAndReturnIt(destinationID) {
|
||||
let destGroupID = false;
|
||||
|
||||
if (destinationID.indexOf("$") >= 0) {
|
||||
|
||||
destGroupID = destinationID.split("$")[0]
|
||||
let groupExists = await groupManager.doesGroupExist(destGroupID);
|
||||
if (destinationID.indexOf('$') >= 0) {
|
||||
destGroupID = destinationID.split('$')[0];
|
||||
const groupExists = await groupManager.doesGroupExist(destGroupID);
|
||||
|
||||
// group does not exist
|
||||
if (!groupExists) {
|
||||
throw new customError("groupID does not exist for destinationID", "apierror");
|
||||
throw new customError('groupID does not exist for destinationID', 'apierror');
|
||||
}
|
||||
}
|
||||
return destGroupID;
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.removePadIfForceIsTrueAndAlreadyExist = async function removePadIfForceIsTrueAndAlreadyExist(destinationID, force) {
|
||||
// if the pad exists, we should abort, unless forced.
|
||||
let exists = await padManager.doesPadExist(destinationID);
|
||||
const exists = await padManager.doesPadExist(destinationID);
|
||||
|
||||
// allow force to be a string
|
||||
if (typeof force === "string") {
|
||||
force = (force.toLowerCase() === "true");
|
||||
if (typeof force === 'string') {
|
||||
force = (force.toLowerCase() === 'true');
|
||||
} else {
|
||||
force = !!force;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
if (!force) {
|
||||
console.error("erroring out without force");
|
||||
throw new customError("destinationID already exists", "apierror");
|
||||
console.error('erroring out without force');
|
||||
throw new customError('destinationID already exists', 'apierror');
|
||||
}
|
||||
|
||||
// exists and forcing
|
||||
let pad = await padManager.getPad(destinationID);
|
||||
const pad = await padManager.getPad(destinationID);
|
||||
await pad.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.copyAuthorInfoToDestinationPad = function copyAuthorInfoToDestinationPad(destinationID) {
|
||||
// add the new sourcePad to all authors who contributed to the old one
|
||||
this.getAllAuthors().forEach(authorID => {
|
||||
this.getAllAuthors().forEach((authorID) => {
|
||||
authorManager.addPad(authorID, destinationID);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Pad.prototype.copyPadWithoutHistory = async function copyPadWithoutHistory(destinationID, force) {
|
||||
let destGroupID;
|
||||
let sourceID = this.id;
|
||||
const sourceID = this.id;
|
||||
|
||||
// flush the source pad
|
||||
this.saveToDatabase();
|
||||
|
@ -490,53 +475,53 @@ Pad.prototype.copyPadWithoutHistory = async function copyPadWithoutHistory(desti
|
|||
|
||||
// if force is true and already exists a Pad with the same id, remove that Pad
|
||||
await this.removePadIfForceIsTrueAndAlreadyExist(destinationID, force);
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
let sourcePad = await padManager.getPad(sourceID);
|
||||
const sourcePad = await padManager.getPad(sourceID);
|
||||
|
||||
// add the new sourcePad to all authors who contributed to the old one
|
||||
this.copyAuthorInfoToDestinationPad(destinationID);
|
||||
|
||||
// Group pad? Add it to the group's list
|
||||
if (destGroupID) {
|
||||
await db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
||||
await db.setSub(`group:${destGroupID}`, ['pads', destinationID], 1);
|
||||
}
|
||||
|
||||
// initialize the pad with a new line to avoid getting the defaultText
|
||||
let newPad = await padManager.getPad(destinationID, '\n');
|
||||
const newPad = await padManager.getPad(destinationID, '\n');
|
||||
|
||||
let oldAText = this.atext;
|
||||
let newPool = newPad.pool;
|
||||
const oldAText = this.atext;
|
||||
const newPool = newPad.pool;
|
||||
newPool.fromJsonable(sourcePad.pool.toJsonable()); // copy that sourceId pool to the new pad
|
||||
|
||||
// based on Changeset.makeSplice
|
||||
let assem = Changeset.smartOpAssembler();
|
||||
const assem = Changeset.smartOpAssembler();
|
||||
assem.appendOpWithText('=', '');
|
||||
Changeset.appendATextToAssembler(oldAText, assem);
|
||||
assem.endDocument();
|
||||
|
||||
// although we have instantiated the newPad with '\n', an additional '\n' is
|
||||
// added internally, so the pad text on the revision 0 is "\n\n"
|
||||
let oldLength = 2;
|
||||
const oldLength = 2;
|
||||
|
||||
let newLength = assem.getLengthChange();
|
||||
let newText = oldAText.text;
|
||||
const newLength = assem.getLengthChange();
|
||||
const newText = oldAText.text;
|
||||
|
||||
// create a changeset that removes the previous text and add the newText with
|
||||
// all atributes present on the source pad
|
||||
let changeset = Changeset.pack(oldLength, newLength, assem.toString(), newText);
|
||||
const changeset = Changeset.pack(oldLength, newLength, assem.toString(), newText);
|
||||
newPad.appendRevision(changeset);
|
||||
|
||||
hooks.callAll('padCopy', { 'originalPad': this, 'destinationID': destinationID });
|
||||
hooks.callAll('padCopy', {originalPad: this, destinationID});
|
||||
|
||||
return { padID: destinationID };
|
||||
}
|
||||
return {padID: destinationID};
|
||||
};
|
||||
|
||||
|
||||
Pad.prototype.remove = async function remove() {
|
||||
var padID = this.id;
|
||||
const padID = this.id;
|
||||
const p = [];
|
||||
|
||||
// kick everyone from this pad
|
||||
|
@ -548,45 +533,44 @@ Pad.prototype.remove = async function remove() {
|
|||
// run to completion
|
||||
|
||||
// is it a group pad? -> delete the entry of this pad in the group
|
||||
if (padID.indexOf("$") >= 0) {
|
||||
|
||||
if (padID.indexOf('$') >= 0) {
|
||||
// it is a group pad
|
||||
let groupID = padID.substring(0, padID.indexOf("$"));
|
||||
let group = await db.get("group:" + groupID);
|
||||
const groupID = padID.substring(0, padID.indexOf('$'));
|
||||
const group = await db.get(`group:${groupID}`);
|
||||
|
||||
// remove the pad entry
|
||||
delete group.pads[padID];
|
||||
|
||||
// set the new value
|
||||
p.push(db.set('group:' + groupID, group));
|
||||
p.push(db.set(`group:${groupID}`, group));
|
||||
}
|
||||
|
||||
// remove the readonly entries
|
||||
p.push(readOnlyManager.getReadOnlyId(padID).then(async (readonlyID) => {
|
||||
await db.remove('readonly2pad:' + readonlyID);
|
||||
await db.remove(`readonly2pad:${readonlyID}`);
|
||||
}));
|
||||
p.push(db.remove('pad2readonly:' + padID));
|
||||
p.push(db.remove(`pad2readonly:${padID}`));
|
||||
|
||||
// delete all chat messages
|
||||
p.push(promises.timesLimit(this.chatHead + 1, 500, async (i) => {
|
||||
await db.remove('pad:' + padID + ':chat:' + i, null);
|
||||
await db.remove(`pad:${padID}:chat:${i}`, null);
|
||||
}));
|
||||
|
||||
// delete all revisions
|
||||
p.push(promises.timesLimit(this.head + 1, 500, async (i) => {
|
||||
await db.remove('pad:' + padID + ':revs:' + i, null);
|
||||
await db.remove(`pad:${padID}:revs:${i}`, null);
|
||||
}));
|
||||
|
||||
// remove pad from all authors who contributed
|
||||
this.getAllAuthors().forEach(authorID => {
|
||||
this.getAllAuthors().forEach((authorID) => {
|
||||
p.push(authorManager.removePad(authorID, padID));
|
||||
});
|
||||
|
||||
// delete the pad entry and delete pad from padManager
|
||||
p.push(padManager.removePad(padID));
|
||||
hooks.callAll("padRemove", { padID });
|
||||
hooks.callAll('padRemove', {padID});
|
||||
await Promise.all(p);
|
||||
}
|
||||
};
|
||||
|
||||
// set in db
|
||||
Pad.prototype.setPublicStatus = async function setPublicStatus(publicStatus) {
|
||||
|
@ -596,17 +580,17 @@ Pad.prototype.setPublicStatus = async function setPublicStatus(publicStatus) {
|
|||
|
||||
Pad.prototype.addSavedRevision = async function addSavedRevision(revNum, savedById, label) {
|
||||
// if this revision is already saved, return silently
|
||||
for (var i in this.savedRevisions) {
|
||||
for (const i in this.savedRevisions) {
|
||||
if (this.savedRevisions[i] && this.savedRevisions[i].revNum === revNum) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// build the saved revision object
|
||||
var savedRevision = {};
|
||||
const savedRevision = {};
|
||||
savedRevision.revNum = revNum;
|
||||
savedRevision.savedById = savedById;
|
||||
savedRevision.label = label || "Revision " + revNum;
|
||||
savedRevision.label = label || `Revision ${revNum}`;
|
||||
savedRevision.timestamp = Date.now();
|
||||
savedRevision.id = randomString(10);
|
||||
|
||||
|
@ -618,4 +602,3 @@ Pad.prototype.addSavedRevision = async function addSavedRevision(revNum, savedBy
|
|||
Pad.prototype.getSavedRevisions = function getSavedRevisions() {
|
||||
return this.savedRevisions;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var customError = require("../utils/customError");
|
||||
var Pad = require("../db/Pad").Pad;
|
||||
var db = require("./DB");
|
||||
const customError = require('../utils/customError');
|
||||
const Pad = require('../db/Pad').Pad;
|
||||
const db = require('./DB');
|
||||
|
||||
/**
|
||||
* A cache of all loaded Pads.
|
||||
|
@ -33,14 +33,14 @@ var db = require("./DB");
|
|||
* If this is needed in other places, it would be wise to make this a prototype
|
||||
* that's defined somewhere more sensible.
|
||||
*/
|
||||
var globalPads = {
|
||||
get: function(name) { return this[':'+name]; },
|
||||
set: function(name, value) {
|
||||
this[':'+name] = value;
|
||||
},
|
||||
remove: function(name) {
|
||||
delete this[':'+name];
|
||||
}
|
||||
const globalPads = {
|
||||
get(name) { return this[`:${name}`]; },
|
||||
set(name, value) {
|
||||
this[`:${name}`] = value;
|
||||
},
|
||||
remove(name) {
|
||||
delete this[`:${name}`];
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,24 +48,24 @@ var globalPads = {
|
|||
*
|
||||
* Updated without db access as new pads are created/old ones removed.
|
||||
*/
|
||||
let padList = {
|
||||
const padList = {
|
||||
list: new Set(),
|
||||
cachedList: undefined,
|
||||
initiated: false,
|
||||
init: async function() {
|
||||
let dbData = await db.findKeys("pad:*", "*:*:*");
|
||||
async init() {
|
||||
const dbData = await db.findKeys('pad:*', '*:*:*');
|
||||
|
||||
if (dbData != null) {
|
||||
this.initiated = true;
|
||||
|
||||
for (let val of dbData) {
|
||||
this.addPad(val.replace(/^pad:/,""), false);
|
||||
for (const val of dbData) {
|
||||
this.addPad(val.replace(/^pad:/, ''), false);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
load: async function() {
|
||||
async load() {
|
||||
if (!this.initiated) {
|
||||
return this.init();
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ let padList = {
|
|||
/**
|
||||
* Returns all pads in alphabetical order as array.
|
||||
*/
|
||||
getPads: async function() {
|
||||
async getPads() {
|
||||
await this.load();
|
||||
|
||||
if (!this.cachedList) {
|
||||
|
@ -84,7 +84,7 @@ let padList = {
|
|||
|
||||
return this.cachedList;
|
||||
},
|
||||
addPad: function(name) {
|
||||
addPad(name) {
|
||||
if (!this.initiated) return;
|
||||
|
||||
if (!this.list.has(name)) {
|
||||
|
@ -92,14 +92,14 @@ let padList = {
|
|||
this.cachedList = undefined;
|
||||
}
|
||||
},
|
||||
removePad: function(name) {
|
||||
removePad(name) {
|
||||
if (!this.initiated) return;
|
||||
|
||||
if (this.list.has(name)) {
|
||||
this.list.delete(name);
|
||||
this.cachedList = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// initialises the all-knowing data structure
|
||||
|
@ -109,22 +109,22 @@ let padList = {
|
|||
* @param id A String with the id of the pad
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.getPad = async function(id, text) {
|
||||
exports.getPad = async function (id, text) {
|
||||
// check if this is a valid padId
|
||||
if (!exports.isValidPadId(id)) {
|
||||
throw new customError(id + " is not a valid padId", "apierror");
|
||||
throw new customError(`${id} is not a valid padId`, 'apierror');
|
||||
}
|
||||
|
||||
// check if this is a valid text
|
||||
if (text != null) {
|
||||
// check if text is a string
|
||||
if (typeof text != "string") {
|
||||
throw new customError("text is not a string", "apierror");
|
||||
if (typeof text !== 'string') {
|
||||
throw new customError('text is not a string', 'apierror');
|
||||
}
|
||||
|
||||
// check if text is less than 100k chars
|
||||
if (text.length > 100000) {
|
||||
throw new customError("text must be less than 100k chars", "apierror");
|
||||
throw new customError('text must be less than 100k chars', 'apierror');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,20 +144,20 @@ exports.getPad = async function(id, text) {
|
|||
padList.addPad(id);
|
||||
|
||||
return pad;
|
||||
}
|
||||
};
|
||||
|
||||
exports.listAllPads = async function() {
|
||||
let padIDs = await padList.getPads();
|
||||
exports.listAllPads = async function () {
|
||||
const padIDs = await padList.getPads();
|
||||
|
||||
return { padIDs };
|
||||
}
|
||||
return {padIDs};
|
||||
};
|
||||
|
||||
// checks if a pad exists
|
||||
exports.doesPadExist = async function(padId) {
|
||||
let value = await db.get("pad:" + padId);
|
||||
exports.doesPadExist = async function (padId) {
|
||||
const value = await db.get(`pad:${padId}`);
|
||||
|
||||
return (value != null && value.atext);
|
||||
}
|
||||
};
|
||||
|
||||
// alias for backwards compatibility
|
||||
exports.doesPadExists = exports.doesPadExist;
|
||||
|
@ -168,42 +168,42 @@ exports.doesPadExists = exports.doesPadExist;
|
|||
*/
|
||||
const padIdTransforms = [
|
||||
[/\s+/g, '_'],
|
||||
[/:+/g, '_']
|
||||
[/:+/g, '_'],
|
||||
];
|
||||
|
||||
// returns a sanitized padId, respecting legacy pad id formats
|
||||
exports.sanitizePadId = async function sanitizePadId(padId) {
|
||||
for (let i = 0, n = padIdTransforms.length; i < n; ++i) {
|
||||
let exists = await exports.doesPadExist(padId);
|
||||
const exists = await exports.doesPadExist(padId);
|
||||
|
||||
if (exists) {
|
||||
return padId;
|
||||
}
|
||||
|
||||
let [from, to] = padIdTransforms[i];
|
||||
const [from, to] = padIdTransforms[i];
|
||||
|
||||
padId = padId.replace(from, to);
|
||||
}
|
||||
|
||||
// we're out of possible transformations, so just return it
|
||||
return padId;
|
||||
}
|
||||
};
|
||||
|
||||
exports.isValidPadId = function(padId) {
|
||||
exports.isValidPadId = function (padId) {
|
||||
return /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the pad from database and unloads it.
|
||||
*/
|
||||
exports.removePad = async (padId) => {
|
||||
const p = db.remove('pad:' + padId);
|
||||
const p = db.remove(`pad:${padId}`);
|
||||
exports.unloadPad(padId);
|
||||
padList.removePad(padId);
|
||||
await p;
|
||||
}
|
||||
};
|
||||
|
||||
// removes a pad from the cache
|
||||
exports.unloadPad = function(padId) {
|
||||
exports.unloadPad = function (padId) {
|
||||
globalPads.remove(padId);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,17 +19,17 @@
|
|||
*/
|
||||
|
||||
|
||||
var db = require("./DB");
|
||||
var randomString = require("../utils/randomstring");
|
||||
const db = require('./DB');
|
||||
const randomString = require('../utils/randomstring');
|
||||
|
||||
|
||||
/**
|
||||
* checks if the id pattern matches a read-only pad id
|
||||
* @param {String} the pad's id
|
||||
*/
|
||||
exports.isReadOnlyId = function(id) {
|
||||
return id.indexOf("r.") === 0;
|
||||
}
|
||||
exports.isReadOnlyId = function (id) {
|
||||
return id.indexOf('r.') === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a read only id for a pad
|
||||
|
@ -37,36 +37,36 @@ exports.isReadOnlyId = function(id) {
|
|||
*/
|
||||
exports.getReadOnlyId = async function (padId) {
|
||||
// check if there is a pad2readonly entry
|
||||
let readOnlyId = await db.get("pad2readonly:" + padId);
|
||||
let readOnlyId = await db.get(`pad2readonly:${padId}`);
|
||||
|
||||
// there is no readOnly Entry in the database, let's create one
|
||||
if (readOnlyId == null) {
|
||||
readOnlyId = "r." + randomString(16);
|
||||
db.set("pad2readonly:" + padId, readOnlyId);
|
||||
db.set("readonly2pad:" + readOnlyId, padId);
|
||||
readOnlyId = `r.${randomString(16)}`;
|
||||
db.set(`pad2readonly:${padId}`, readOnlyId);
|
||||
db.set(`readonly2pad:${readOnlyId}`, padId);
|
||||
}
|
||||
|
||||
return readOnlyId;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the padId for a read only id
|
||||
* @param {String} readOnlyId read only id
|
||||
*/
|
||||
exports.getPadId = function(readOnlyId) {
|
||||
return db.get("readonly2pad:" + readOnlyId);
|
||||
}
|
||||
exports.getPadId = function (readOnlyId) {
|
||||
return db.get(`readonly2pad:${readOnlyId}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the padId and readonlyPadId in an object for any id
|
||||
* @param {String} padIdOrReadonlyPadId read only id or real pad id
|
||||
*/
|
||||
exports.getIds = async function(id) {
|
||||
let readonly = (id.indexOf("r.") === 0);
|
||||
exports.getIds = async function (id) {
|
||||
const readonly = (id.indexOf('r.') === 0);
|
||||
|
||||
// Might be null, if this is an unknown read-only id
|
||||
let readOnlyPadId = readonly ? id : await exports.getReadOnlyId(id);
|
||||
let padId = readonly ? await exports.getPadId(id) : id;
|
||||
const readOnlyPadId = readonly ? id : await exports.getReadOnlyId(id);
|
||||
const padId = readonly ? await exports.getPadId(id) : id;
|
||||
|
||||
return { readOnlyPadId, padId, readonly };
|
||||
}
|
||||
return {readOnlyPadId, padId, readonly};
|
||||
};
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var authorManager = require("./AuthorManager");
|
||||
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
var settings = require("../utils/Settings");
|
||||
const authorManager = require('./AuthorManager');
|
||||
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks.js');
|
||||
const padManager = require('./PadManager');
|
||||
const sessionManager = require('./SessionManager');
|
||||
const settings = require('../utils/Settings');
|
||||
const webaccess = require('../hooks/express/webaccess');
|
||||
var log4js = require('log4js');
|
||||
var authLogger = log4js.getLogger("auth");
|
||||
const log4js = require('log4js');
|
||||
const authLogger = log4js.getLogger('auth');
|
||||
|
||||
const DENY = Object.freeze({accessStatus: 'deny'});
|
||||
|
||||
|
@ -47,7 +47,7 @@ const DENY = Object.freeze({accessStatus: 'deny'});
|
|||
* WARNING: Tokens and session IDs MUST be kept secret, otherwise users will be able to impersonate
|
||||
* each other (which might allow them to gain privileges).
|
||||
*/
|
||||
exports.checkAccess = async function(padID, sessionCookie, token, userSettings) {
|
||||
exports.checkAccess = async function (padID, sessionCookie, token, userSettings) {
|
||||
if (!padID) {
|
||||
authLogger.debug('access denied: missing padID');
|
||||
return DENY;
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var customError = require("../utils/customError");
|
||||
const customError = require('../utils/customError');
|
||||
const promises = require('../utils/promises');
|
||||
var randomString = require("../utils/randomstring");
|
||||
var db = require("./DB");
|
||||
var groupManager = require("./GroupManager");
|
||||
var authorManager = require("./AuthorManager");
|
||||
const randomString = require('../utils/randomstring');
|
||||
const db = require('./DB');
|
||||
const groupManager = require('./GroupManager');
|
||||
const authorManager = require('./AuthorManager');
|
||||
|
||||
/**
|
||||
* Finds the author ID for a session with matching ID and group.
|
||||
|
@ -78,61 +78,61 @@ exports.findAuthorID = async (groupID, sessionCookie) => {
|
|||
return sessionInfo.authorID;
|
||||
};
|
||||
|
||||
exports.doesSessionExist = async function(sessionID) {
|
||||
//check if the database entry of this session exists
|
||||
let session = await db.get("session:" + sessionID);
|
||||
exports.doesSessionExist = async function (sessionID) {
|
||||
// check if the database entry of this session exists
|
||||
const session = await db.get(`session:${sessionID}`);
|
||||
return (session !== null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new session between an author and a group
|
||||
*/
|
||||
exports.createSession = async function(groupID, authorID, validUntil) {
|
||||
exports.createSession = async function (groupID, authorID, validUntil) {
|
||||
// check if the group exists
|
||||
let groupExists = await groupManager.doesGroupExist(groupID);
|
||||
const groupExists = await groupManager.doesGroupExist(groupID);
|
||||
if (!groupExists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
throw new customError('groupID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// check if the author exists
|
||||
let authorExists = await authorManager.doesAuthorExist(authorID);
|
||||
const authorExists = await authorManager.doesAuthorExist(authorID);
|
||||
if (!authorExists) {
|
||||
throw new customError("authorID does not exist", "apierror");
|
||||
throw new customError('authorID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// try to parse validUntil if it's not a number
|
||||
if (typeof validUntil !== "number") {
|
||||
if (typeof validUntil !== 'number') {
|
||||
validUntil = parseInt(validUntil);
|
||||
}
|
||||
|
||||
// check it's a valid number
|
||||
if (isNaN(validUntil)) {
|
||||
throw new customError("validUntil is not a number", "apierror");
|
||||
throw new customError('validUntil is not a number', 'apierror');
|
||||
}
|
||||
|
||||
// ensure this is not a negative number
|
||||
if (validUntil < 0) {
|
||||
throw new customError("validUntil is a negative number", "apierror");
|
||||
throw new customError('validUntil is a negative number', 'apierror');
|
||||
}
|
||||
|
||||
// ensure this is not a float value
|
||||
if (!is_int(validUntil)) {
|
||||
throw new customError("validUntil is a float value", "apierror");
|
||||
throw new customError('validUntil is a float value', 'apierror');
|
||||
}
|
||||
|
||||
// check if validUntil is in the future
|
||||
if (validUntil < Math.floor(Date.now() / 1000)) {
|
||||
throw new customError("validUntil is in the past", "apierror");
|
||||
throw new customError('validUntil is in the past', 'apierror');
|
||||
}
|
||||
|
||||
// generate sessionID
|
||||
let sessionID = "s." + randomString(16);
|
||||
const sessionID = `s.${randomString(16)}`;
|
||||
|
||||
// set the session into the database
|
||||
await db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
||||
await db.set(`session:${sessionID}`, {groupID, authorID, validUntil});
|
||||
|
||||
// get the entry
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
let group2sessions = await db.get(`group2sessions:${groupID}`);
|
||||
|
||||
/*
|
||||
* In some cases, the db layer could return "undefined" as well as "null".
|
||||
|
@ -144,115 +144,115 @@ exports.createSession = async function(groupID, authorID, validUntil) {
|
|||
*/
|
||||
if (!group2sessions || !group2sessions.sessionIDs) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
group2sessions = {sessionIDs : {}};
|
||||
group2sessions = {sessionIDs: {}};
|
||||
}
|
||||
|
||||
// add the entry for this session
|
||||
group2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
// save the new element back
|
||||
await db.set("group2sessions:" + groupID, group2sessions);
|
||||
await db.set(`group2sessions:${groupID}`, group2sessions);
|
||||
|
||||
// get the author2sessions entry
|
||||
let author2sessions = await db.get("author2sessions:" + authorID);
|
||||
let author2sessions = await db.get(`author2sessions:${authorID}`);
|
||||
|
||||
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
|
||||
author2sessions.sessionIDs[sessionID] = 1;
|
||||
|
||||
//save the new element back
|
||||
await db.set("author2sessions:" + authorID, author2sessions);
|
||||
// save the new element back
|
||||
await db.set(`author2sessions:${authorID}`, author2sessions);
|
||||
|
||||
return { sessionID };
|
||||
}
|
||||
return {sessionID};
|
||||
};
|
||||
|
||||
exports.getSessionInfo = async function(sessionID) {
|
||||
exports.getSessionInfo = async function (sessionID) {
|
||||
// check if the database entry of this session exists
|
||||
let session = await db.get("session:" + sessionID);
|
||||
const session = await db.get(`session:${sessionID}`);
|
||||
|
||||
if (session == null) {
|
||||
// session does not exist
|
||||
throw new customError("sessionID does not exist", "apierror");
|
||||
throw new customError('sessionID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// everything is fine, return the sessioninfos
|
||||
return session;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a session
|
||||
*/
|
||||
exports.deleteSession = async function(sessionID) {
|
||||
exports.deleteSession = async function (sessionID) {
|
||||
// ensure that the session exists
|
||||
let session = await db.get("session:" + sessionID);
|
||||
const session = await db.get(`session:${sessionID}`);
|
||||
if (session == null) {
|
||||
throw new customError("sessionID does not exist", "apierror");
|
||||
throw new customError('sessionID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
// everything is fine, use the sessioninfos
|
||||
let groupID = session.groupID;
|
||||
let authorID = session.authorID;
|
||||
const groupID = session.groupID;
|
||||
const authorID = session.authorID;
|
||||
|
||||
// get the group2sessions and author2sessions entries
|
||||
let group2sessions = await db.get("group2sessions:" + groupID);
|
||||
let author2sessions = await db.get("author2sessions:" + authorID);
|
||||
const group2sessions = await db.get(`group2sessions:${groupID}`);
|
||||
const author2sessions = await db.get(`author2sessions:${authorID}`);
|
||||
|
||||
// remove the session
|
||||
await db.remove("session:" + sessionID);
|
||||
await db.remove(`session:${sessionID}`);
|
||||
|
||||
// remove session from group2sessions
|
||||
if (group2sessions != null) { // Maybe the group was already deleted
|
||||
delete group2sessions.sessionIDs[sessionID];
|
||||
await db.set("group2sessions:" + groupID, group2sessions);
|
||||
await db.set(`group2sessions:${groupID}`, group2sessions);
|
||||
}
|
||||
|
||||
// remove session from author2sessions
|
||||
if (author2sessions != null) { // Maybe the author was already deleted
|
||||
delete author2sessions.sessionIDs[sessionID];
|
||||
await db.set("author2sessions:" + authorID, author2sessions);
|
||||
await db.set(`author2sessions:${authorID}`, author2sessions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.listSessionsOfGroup = async function(groupID) {
|
||||
exports.listSessionsOfGroup = async function (groupID) {
|
||||
// check that the group exists
|
||||
let exists = await groupManager.doesGroupExist(groupID);
|
||||
const exists = await groupManager.doesGroupExist(groupID);
|
||||
if (!exists) {
|
||||
throw new customError("groupID does not exist", "apierror");
|
||||
throw new customError('groupID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
let sessions = await listSessionsWithDBKey("group2sessions:" + groupID);
|
||||
const sessions = await listSessionsWithDBKey(`group2sessions:${groupID}`);
|
||||
return sessions;
|
||||
}
|
||||
};
|
||||
|
||||
exports.listSessionsOfAuthor = async function(authorID) {
|
||||
exports.listSessionsOfAuthor = async function (authorID) {
|
||||
// check that the author exists
|
||||
let exists = await authorManager.doesAuthorExist(authorID)
|
||||
const exists = await authorManager.doesAuthorExist(authorID);
|
||||
if (!exists) {
|
||||
throw new customError("authorID does not exist", "apierror");
|
||||
throw new customError('authorID does not exist', 'apierror');
|
||||
}
|
||||
|
||||
let sessions = await listSessionsWithDBKey("author2sessions:" + authorID);
|
||||
const sessions = await listSessionsWithDBKey(`author2sessions:${authorID}`);
|
||||
return sessions;
|
||||
}
|
||||
};
|
||||
|
||||
// this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
// required to return null rather than an empty object if there are none
|
||||
async function listSessionsWithDBKey(dbkey) {
|
||||
// get the group2sessions entry
|
||||
let sessionObject = await db.get(dbkey);
|
||||
let sessions = sessionObject ? sessionObject.sessionIDs : null;
|
||||
const sessionObject = await db.get(dbkey);
|
||||
const sessions = sessionObject ? sessionObject.sessionIDs : null;
|
||||
|
||||
// iterate through the sessions and get the sessioninfos
|
||||
for (let sessionID in sessions) {
|
||||
for (const sessionID in sessions) {
|
||||
try {
|
||||
let sessionInfo = await exports.getSessionInfo(sessionID);
|
||||
const sessionInfo = await exports.getSessionInfo(sessionID);
|
||||
sessions[sessionID] = sessionInfo;
|
||||
} catch (err) {
|
||||
if (err == "apierror: sessionID does not exist") {
|
||||
if (err == 'apierror: sessionID does not exist') {
|
||||
console.warn(`Found bad session ${sessionID} in ${dbkey}`);
|
||||
sessions[sessionID] = null;
|
||||
} else {
|
||||
|
|
|
@ -15,11 +15,11 @@ const logger = log4js.getLogger('SessionStore');
|
|||
|
||||
module.exports = class SessionStore extends Store {
|
||||
get(sid, fn) {
|
||||
logger.debug('GET ' + sid);
|
||||
DB.db.get('sessionstorage:' + sid, (err, sess) => {
|
||||
logger.debug(`GET ${sid}`);
|
||||
DB.db.get(`sessionstorage:${sid}`, (err, 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) {
|
||||
fn(null, sess);
|
||||
} else {
|
||||
|
@ -32,12 +32,12 @@ module.exports = class SessionStore extends Store {
|
|||
}
|
||||
|
||||
set(sid, sess, fn) {
|
||||
logger.debug('SET ' + sid);
|
||||
DB.db.set('sessionstorage:' + sid, sess, fn);
|
||||
logger.debug(`SET ${sid}`);
|
||||
DB.db.set(`sessionstorage:${sid}`, sess, fn);
|
||||
}
|
||||
|
||||
destroy(sid, fn) {
|
||||
logger.debug('DESTROY ' + sid);
|
||||
DB.db.remove('sessionstorage:' + sid, fn);
|
||||
logger.debug(`DESTROY ${sid}`);
|
||||
DB.db.remove(`sessionstorage:${sid}`, fn);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue