lint: Run eslint --fix on src/

This commit is contained in:
Richard Hansen 2020-11-23 13:24:19 -05:00 committed by John McLear
parent b8d07a42eb
commit 8e5fd19db2
109 changed files with 9061 additions and 10572 deletions

View file

@ -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&#x3a;&#x2F;&#x2F;etherpad&#x2e;org\">http:&#x2F;&#x2F;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');
}
}

View file

@ -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);
}
}
};

View file

@ -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();

View file

@ -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};
};

View file

@ -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;
};

View file

@ -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);
}
};

View file

@ -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};
};

View file

@ -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;

View file

@ -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 {

View file

@ -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);
}
};