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,7 +18,7 @@ let serverName;
exports.server = null;
exports.createServer = async () => {
console.log("Report bugs at https://github.com/ether/etherpad-lite/issues")
console.log('Report bugs at https://github.com/ether/etherpad-lite/issues');
serverName = `Etherpad ${settings.getGitCommit()} (https://etherpad.org)`;
@ -26,7 +26,7 @@ exports.createServer = async () => {
await exports.restartServer();
if (settings.ip === "") {
if (settings.ip === '') {
// using Unix socket for connectivity
console.log(`You can access your Etherpad instance using the Unix socket at ${settings.port}`);
} else {
@ -42,26 +42,26 @@ exports.createServer = async () => {
const env = process.env.NODE_ENV || 'development';
if (env !== 'production') {
console.warn("Etherpad is running in Development mode. This mode is slower for users and less secure than production mode. You should set the NODE_ENV environment variable to production by using: export NODE_ENV=production");
console.warn('Etherpad is running in Development mode. This mode is slower for users and less secure than production mode. You should set the NODE_ENV environment variable to production by using: export NODE_ENV=production');
}
}
};
exports.restartServer = async () => {
if (exports.server) {
console.log("Restarting express server");
console.log('Restarting express server');
await util.promisify(exports.server.close).bind(exports.server)();
}
const app = express(); // New syntax for express v3
if (settings.ssl) {
console.log("SSL -- enabled");
console.log('SSL -- enabled');
console.log(`SSL -- server key file: ${settings.ssl.key}`);
console.log(`SSL -- Certificate Authority's certificate file: ${settings.ssl.cert}`);
const options = {
key: fs.readFileSync( settings.ssl.key ),
cert: fs.readFileSync( settings.ssl.cert )
key: fs.readFileSync(settings.ssl.key),
cert: fs.readFileSync(settings.ssl.cert),
};
if (settings.ssl.ca) {
@ -79,16 +79,16 @@ exports.restartServer = async () => {
exports.server = http.createServer(app);
}
app.use(function(req, res, next) {
app.use((req, res, next) => {
// res.header("X-Frame-Options", "deny"); // breaks embedded pads
if (settings.ssl) {
// we use SSL
res.header("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
res.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
// Stop IE going into compatability mode
// https://github.com/ether/etherpad-lite/issues/2547
res.header("X-UA-Compatible", "IE=Edge,chrome=1");
res.header('X-UA-Compatible', 'IE=Edge,chrome=1');
// Enable a strong referrer policy. Same-origin won't drop Referers when
// loading local resources, but it will drop them when loading foreign resources.
@ -97,11 +97,11 @@ exports.restartServer = async () => {
// marked with <meta name="referrer" content="no-referrer">
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
// https://github.com/ether/etherpad-lite/pull/3636
res.header("Referrer-Policy", "same-origin");
res.header('Referrer-Policy', 'same-origin');
// send git version in the Server response header if exposeVersion is true.
if (settings.exposeVersion) {
res.header("Server", serverName);
res.header('Server', serverName);
}
next();
@ -165,13 +165,13 @@ exports.restartServer = async () => {
//
// reference: https://github.com/expressjs/session/blob/v1.17.0/README.md#cookiesecure
secure: 'auto',
}
},
});
app.use(exports.sessionMiddleware);
app.use(cookieParser(settings.sessionKey, {}));
hooks.callAll("expressConfigure", {"app": app});
hooks.callAll('expressConfigure', {app});
hooks.callAll('expressCreateServer', {app, server: exports.server});
await util.promisify(exports.server.listen).bind(exports.server)(settings.port, settings.ip);

View file

@ -1,9 +1,9 @@
var eejs = require('ep_etherpad-lite/node/eejs');
const eejs = require('ep_etherpad-lite/node/eejs');
exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/admin', function(req, res) {
if('/' != req.path[req.path.length-1]) return res.redirect('./admin/');
args.app.get('/admin', (req, res) => {
if ('/' != req.path[req.path.length - 1]) return res.redirect('./admin/');
res.send(eejs.require('ep_etherpad-lite/templates/admin/index.html', {req}));
});
return cb();
}
};

View file

@ -1,13 +1,13 @@
var eejs = require('ep_etherpad-lite/node/eejs');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var installer = require('ep_etherpad-lite/static/js/pluginfw/installer');
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs');
var _ = require('underscore');
var semver = require('semver');
const eejs = require('ep_etherpad-lite/node/eejs');
const settings = require('ep_etherpad-lite/node/utils/Settings');
const installer = require('ep_etherpad-lite/static/js/pluginfw/installer');
const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs');
const _ = require('underscore');
const semver = require('semver');
const UpdateCheck = require('ep_etherpad-lite/node/utils/UpdateCheck');
exports.expressCreateServer = function(hook_name, args, cb) {
args.app.get('/admin/plugins', function(req, res) {
exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/admin/plugins', (req, res) => {
res.send(eejs.require('ep_etherpad-lite/templates/admin/plugins.html', {
plugins: plugins.plugins,
req,
@ -16,114 +16,108 @@ exports.expressCreateServer = function(hook_name, args, cb) {
}));
});
args.app.get('/admin/plugins/info', function(req, res) {
var gitCommit = settings.getGitCommit();
var epVersion = settings.getEpVersion();
args.app.get('/admin/plugins/info', (req, res) => {
const gitCommit = settings.getGitCommit();
const epVersion = settings.getEpVersion();
res.send(eejs.require("ep_etherpad-lite/templates/admin/plugins-info.html", {
gitCommit: gitCommit,
epVersion: epVersion,
res.send(eejs.require('ep_etherpad-lite/templates/admin/plugins-info.html', {
gitCommit,
epVersion,
latestVersion: UpdateCheck.getLatestVersion(),
req,
}));
});
return cb();
}
};
exports.socketio = function(hook_name, args, cb) {
var io = args.io.of("/pluginfw/installer");
io.on('connection', function(socket) {
exports.socketio = function (hook_name, args, cb) {
const io = args.io.of('/pluginfw/installer');
io.on('connection', (socket) => {
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
socket.on("getInstalled", function(query) {
socket.on('getInstalled', (query) => {
// send currently installed plugins
var installed = Object.keys(plugins.plugins).map(function(plugin) {
return plugins.plugins[plugin].package
});
const installed = Object.keys(plugins.plugins).map((plugin) => plugins.plugins[plugin].package);
socket.emit("results:installed", {installed: installed});
socket.emit('results:installed', {installed});
});
socket.on("checkUpdates", async function() {
socket.on('checkUpdates', async () => {
// Check plugins for updates
try {
let results = await installer.getAvailablePlugins(/*maxCacheAge:*/ 60 * 10);
const results = await installer.getAvailablePlugins(/* maxCacheAge:*/ 60 * 10);
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
const updatable = _(plugins.plugins).keys().filter((plugin) => {
if (!results[plugin]) return false;
var latestVersion = results[plugin].version;
var currentVersion = plugins.plugins[plugin].package.version;
const latestVersion = results[plugin].version;
const currentVersion = plugins.plugins[plugin].package.version;
return semver.gt(latestVersion, currentVersion);
});
socket.emit("results:updatable", {updatable: updatable});
socket.emit('results:updatable', {updatable});
} catch (er) {
console.warn(er);
socket.emit("results:updatable", {updatable: {}});
socket.emit('results:updatable', {updatable: {}});
}
});
socket.on("getAvailable", async function(query) {
socket.on('getAvailable', async (query) => {
try {
let results = await installer.getAvailablePlugins(/*maxCacheAge:*/ false);
socket.emit("results:available", results);
const results = await installer.getAvailablePlugins(/* maxCacheAge:*/ false);
socket.emit('results:available', results);
} catch (er) {
console.error(er);
socket.emit("results:available", {});
socket.emit('results:available', {});
}
});
socket.on("search", async function(query) {
socket.on('search', async (query) => {
try {
let results = await installer.search(query.searchTerm, /*maxCacheAge:*/ 60 * 10);
var res = Object.keys(results)
.map(function(pluginName) {
return results[pluginName];
})
.filter(function(plugin) {
return !plugins.plugins[plugin.name];
});
const results = await installer.search(query.searchTerm, /* maxCacheAge:*/ 60 * 10);
let res = Object.keys(results)
.map((pluginName) => results[pluginName])
.filter((plugin) => !plugins.plugins[plugin.name]);
res = sortPluginList(res, query.sortBy, query.sortDir)
.slice(query.offset, query.offset+query.limit);
socket.emit("results:search", {results: res, query: query});
.slice(query.offset, query.offset + query.limit);
socket.emit('results:search', {results: res, query});
} catch (er) {
console.error(er);
socket.emit("results:search", {results: {}, query: query});
socket.emit('results:search', {results: {}, query});
}
});
socket.on("install", function(plugin_name) {
installer.install(plugin_name, function(er) {
socket.on('install', (plugin_name) => {
installer.install(plugin_name, (er) => {
if (er) console.warn(er);
socket.emit("finished:install", {plugin: plugin_name, code: er? er.code : null, error: er? er.message : null});
socket.emit('finished:install', {plugin: plugin_name, code: er ? er.code : null, error: er ? er.message : null});
});
});
socket.on("uninstall", function(plugin_name) {
installer.uninstall(plugin_name, function(er) {
socket.on('uninstall', (plugin_name) => {
installer.uninstall(plugin_name, (er) => {
if (er) console.warn(er);
socket.emit("finished:uninstall", {plugin: plugin_name, error: er? er.message : null});
socket.emit('finished:uninstall', {plugin: plugin_name, error: er ? er.message : null});
});
});
});
return cb();
}
};
function sortPluginList(plugins, property, /*ASC?*/dir) {
return plugins.sort(function(a, b) {
function sortPluginList(plugins, property, /* ASC?*/dir) {
return plugins.sort((a, b) => {
if (a[property] < b[property]) {
return dir? -1 : 1;
return dir ? -1 : 1;
}
if (a[property] > b[property]) {
return dir? 1 : -1;
return dir ? 1 : -1;
}
// a must be equal to b

View file

@ -1,55 +1,52 @@
var eejs = require('ep_etherpad-lite/node/eejs');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
var fs = require('fs');
const eejs = require('ep_etherpad-lite/node/eejs');
const settings = require('ep_etherpad-lite/node/utils/Settings');
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
const fs = require('fs');
exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/admin/settings', function(req, res) {
args.app.get('/admin/settings', (req, res) => {
res.send(eejs.require('ep_etherpad-lite/templates/admin/settings.html', {
req,
settings: "",
settings: '',
search_results: {},
errors: []
errors: [],
}));
});
return cb();
}
};
exports.socketio = function (hook_name, args, cb) {
var io = args.io.of("/settings");
io.on('connection', function (socket) {
const io = args.io.of('/settings');
io.on('connection', (socket) => {
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
socket.on("load", function (query) {
fs.readFile('settings.json', 'utf8', function (err,data) {
socket.on('load', (query) => {
fs.readFile('settings.json', 'utf8', (err, data) => {
if (err) {
return console.log(err);
}
// if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result
if(settings.showSettingsInAdminPage === false) {
socket.emit("settings", {results: 'NOT_ALLOWED'});
}
else {
socket.emit("settings", {results: data});
if (settings.showSettingsInAdminPage === false) {
socket.emit('settings', {results: 'NOT_ALLOWED'});
} else {
socket.emit('settings', {results: data});
}
});
});
socket.on("saveSettings", function (settings) {
fs.writeFile('settings.json', settings, function (err) {
socket.on('saveSettings', (settings) => {
fs.writeFile('settings.json', settings, (err) => {
if (err) throw err;
socket.emit("saveprogress", "saved");
socket.emit('saveprogress', 'saved');
});
});
socket.on('restartServer', async () => {
console.log("Admin request to restart server through a socket on /admin/settings");
console.log('Admin request to restart server through a socket on /admin/settings');
settings.reloadSettings();
await hooks.aCallAll('restartServer');
});
});
return cb();
}
};

View file

@ -1,34 +1,34 @@
var log4js = require('log4js');
var clientLogger = log4js.getLogger("client");
var formidable = require('formidable');
var apiHandler = require('../../handler/APIHandler');
const log4js = require('log4js');
const clientLogger = log4js.getLogger('client');
const formidable = require('formidable');
const apiHandler = require('../../handler/APIHandler');
exports.expressCreateServer = function (hook_name, args, cb) {
//The Etherpad client side sends information about how a disconnect happened
args.app.post('/ep/pad/connection-diagnostic-info', function(req, res) {
new formidable.IncomingForm().parse(req, function(err, fields, files) {
clientLogger.info("DIAGNOSTIC-INFO: " + fields.diagnosticInfo);
res.end("OK");
// The Etherpad client side sends information about how a disconnect happened
args.app.post('/ep/pad/connection-diagnostic-info', (req, res) => {
new formidable.IncomingForm().parse(req, (err, fields, files) => {
clientLogger.info(`DIAGNOSTIC-INFO: ${fields.diagnosticInfo}`);
res.end('OK');
});
});
//The Etherpad client side sends information about client side javscript errors
args.app.post('/jserror', function(req, res) {
new formidable.IncomingForm().parse(req, function(err, fields, files) {
// The Etherpad client side sends information about client side javscript errors
args.app.post('/jserror', (req, res) => {
new formidable.IncomingForm().parse(req, (err, fields, files) => {
try {
var data = JSON.parse(fields.errorInfo)
}catch(e){
return res.end()
var data = JSON.parse(fields.errorInfo);
} catch (e) {
return res.end();
}
clientLogger.warn(data.msg+' --', data);
res.end("OK");
clientLogger.warn(`${data.msg} --`, data);
res.end('OK');
});
});
//Provide a possibility to query the latest available API version
args.app.get('/api', function (req, res) {
res.json({"currentVersion" : apiHandler.latestApiVersion});
// Provide a possibility to query the latest available API version
args.app.get('/api', (req, res) => {
res.json({currentVersion: apiHandler.latestApiVersion});
});
return cb();
}
};

View file

@ -1,17 +1,17 @@
var stats = require('ep_etherpad-lite/node/stats')
const stats = require('ep_etherpad-lite/node/stats');
exports.expressCreateServer = function (hook_name, args, cb) {
exports.app = args.app;
// Handle errors
args.app.use(function(err, req, res, next) {
args.app.use((err, req, res, next) => {
// if an error occurs Connect will pass it down
// through these "error-handling" middleware
// allowing you to respond however you like
res.status(500).send({ error: 'Sorry, something bad happened!' });
console.error(err.stack? err.stack : err.toString());
stats.meter('http500').mark()
res.status(500).send({error: 'Sorry, something bad happened!'});
console.error(err.stack ? err.stack : err.toString());
stats.meter('http500').mark();
});
return cb();
}
};

View file

@ -1,44 +1,43 @@
const assert = require('assert').strict;
var hasPadAccess = require("../../padaccess");
var settings = require('../../utils/Settings');
var exportHandler = require('../../handler/ExportHandler');
var importHandler = require('../../handler/ImportHandler');
var padManager = require("../../db/PadManager");
var readOnlyManager = require("../../db/ReadOnlyManager");
var authorManager = require("../../db/AuthorManager");
const rateLimit = require("express-rate-limit");
const securityManager = require("../../db/SecurityManager");
const webaccess = require("./webaccess");
const hasPadAccess = require('../../padaccess');
const settings = require('../../utils/Settings');
const exportHandler = require('../../handler/ExportHandler');
const importHandler = require('../../handler/ImportHandler');
const padManager = require('../../db/PadManager');
const readOnlyManager = require('../../db/ReadOnlyManager');
const authorManager = require('../../db/AuthorManager');
const rateLimit = require('express-rate-limit');
const securityManager = require('../../db/SecurityManager');
const webaccess = require('./webaccess');
settings.importExportRateLimiting.onLimitReached = function(req, res, options) {
settings.importExportRateLimiting.onLimitReached = function (req, res, options) {
// when the rate limiter triggers, write a warning in the logs
console.warn(`Import/Export rate limiter triggered on "${req.originalUrl}" for IP address ${req.ip}`);
}
};
var limiter = rateLimit(settings.importExportRateLimiting);
const limiter = rateLimit(settings.importExportRateLimiting);
exports.expressCreateServer = function (hook_name, args, cb) {
// handle export requests
args.app.use('/p/:pad/:rev?/export/:type', limiter);
args.app.get('/p/:pad/:rev?/export/:type', async function(req, res, next) {
var types = ["pdf", "doc", "txt", "html", "odt", "etherpad"];
//send a 404 if we don't support this filetype
args.app.get('/p/:pad/:rev?/export/:type', async (req, res, next) => {
const types = ['pdf', 'doc', 'txt', 'html', 'odt', 'etherpad'];
// send a 404 if we don't support this filetype
if (types.indexOf(req.params.type) == -1) {
return next();
}
// if abiword is disabled, and this is a format we only support with abiword, output a message
if (settings.exportAvailable() == "no" &&
["odt", "pdf", "doc"].indexOf(req.params.type) !== -1) {
if (settings.exportAvailable() == 'no' &&
['odt', 'pdf', 'doc'].indexOf(req.params.type) !== -1) {
console.error(`Impossible to export pad "${req.params.pad}" in ${req.params.type} format. There is no converter configured`);
// ACHTUNG: do not include req.params.type in res.send() because there is no HTML escaping and it would lead to an XSS
res.send("This export is not enabled at this Etherpad instance. Set the path to Abiword or soffice (LibreOffice) in settings.json to enable this feature");
res.send('This export is not enabled at this Etherpad instance. Set the path to Abiword or soffice (LibreOffice) in settings.json to enable this feature');
return;
}
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Origin', '*');
if (await hasPadAccess(req, res)) {
let padId = req.params.pad;
@ -49,7 +48,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
padId = await readOnlyManager.getPadId(readOnlyId);
}
let exists = await padManager.doesPadExists(padId);
const exists = await padManager.doesPadExists(padId);
if (!exists) {
console.warn(`Someone tried to export a pad that doesn't exist (${padId})`);
return next();
@ -62,7 +61,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// handle import requests
args.app.use('/p/:pad/import', limiter);
args.app.post('/p/:pad/import', async function(req, res, next) {
args.app.post('/p/:pad/import', async (req, res, next) => {
const {session: {user} = {}} = req;
const {accessStatus} = await securityManager.checkAccess(
req.params.pad, req.cookies.sessionID, req.cookies.token, user);
@ -73,4 +72,4 @@ exports.expressCreateServer = function (hook_name, args, cb) {
});
return cb();
}
};

View file

@ -62,14 +62,14 @@ const RESERVED_WORDS = [
'volatile',
'while',
'with',
'yield'
'yield',
];
const regex = /^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/;
module.exports.check = function(inputStr) {
var isValid = true;
inputStr.split(".").forEach(function(part) {
module.exports.check = function (inputStr) {
let isValid = true;
inputStr.split('.').forEach((part) => {
if (!regex.test(part)) {
isValid = false;
}
@ -80,4 +80,4 @@ module.exports.check = function(inputStr) {
});
return isValid;
}
};

View file

@ -14,7 +14,7 @@
const OpenAPIBackend = require('openapi-backend').default;
const formidable = require('formidable');
const { promisify } = require('util');
const {promisify} = require('util');
const cloneDeep = require('lodash.clonedeep');
const createHTTPError = require('http-errors');
@ -57,12 +57,12 @@ const resources = {
create: {
operationId: 'createGroup',
summary: 'creates a new group',
responseSchema: { groupID: { type: 'string' } },
responseSchema: {groupID: {type: 'string'}},
},
createIfNotExistsFor: {
operationId: 'createGroupIfNotExistsFor',
summary: 'this functions helps you to map your application group ids to Etherpad group ids',
responseSchema: { groupID: { type: 'string' } },
responseSchema: {groupID: {type: 'string'}},
},
delete: {
operationId: 'deleteGroup',
@ -71,7 +71,7 @@ const resources = {
listPads: {
operationId: 'listPads',
summary: 'returns all pads of this group',
responseSchema: { padIDs: { type: 'array', items: { type: 'string' } } },
responseSchema: {padIDs: {type: 'array', items: {type: 'string'}}},
},
createPad: {
operationId: 'createGroupPad',
@ -80,12 +80,12 @@ const resources = {
listSessions: {
operationId: 'listSessionsOfGroup',
summary: '',
responseSchema: { sessions: { type: 'array', items: { $ref: '#/components/schemas/SessionInfo' } } },
responseSchema: {sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}},
},
list: {
operationId: 'listAllGroups',
summary: '',
responseSchema: { groupIDs: { type: 'array', items: { type: 'string' } } },
responseSchema: {groupIDs: {type: 'array', items: {type: 'string'}}},
},
},
@ -94,28 +94,28 @@ const resources = {
create: {
operationId: 'createAuthor',
summary: 'creates a new author',
responseSchema: { authorID: { type: 'string' } },
responseSchema: {authorID: {type: 'string'}},
},
createIfNotExistsFor: {
operationId: 'createAuthorIfNotExistsFor',
summary: 'this functions helps you to map your application author ids to Etherpad author ids',
responseSchema: { authorID: { type: 'string' } },
responseSchema: {authorID: {type: 'string'}},
},
listPads: {
operationId: 'listPadsOfAuthor',
summary: 'returns an array of all pads this author contributed to',
responseSchema: { padIDs: { type: 'array', items: { type: 'string' } } },
responseSchema: {padIDs: {type: 'array', items: {type: 'string'}}},
},
listSessions: {
operationId: 'listSessionsOfAuthor',
summary: 'returns all sessions of an author',
responseSchema: { sessions: { type: 'array', items: { $ref: '#/components/schemas/SessionInfo' } } },
responseSchema: {sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}},
},
// We need an operation that return a UserInfo so it can be picked up by the codegen :(
getName: {
operationId: 'getAuthorName',
summary: 'Returns the Author Name of the author',
responseSchema: { info: { $ref: '#/components/schemas/UserInfo' } },
responseSchema: {info: {$ref: '#/components/schemas/UserInfo'}},
},
},
@ -124,7 +124,7 @@ const resources = {
create: {
operationId: 'createSession',
summary: 'creates a new session. validUntil is an unix timestamp in seconds',
responseSchema: { sessionID: { type: 'string' } },
responseSchema: {sessionID: {type: 'string'}},
},
delete: {
operationId: 'deleteSession',
@ -134,7 +134,7 @@ const resources = {
info: {
operationId: 'getSessionInfo',
summary: 'returns informations about a session',
responseSchema: { info: { $ref: '#/components/schemas/SessionInfo' } },
responseSchema: {info: {$ref: '#/components/schemas/SessionInfo'}},
},
},
@ -143,7 +143,7 @@ const resources = {
listAll: {
operationId: 'listAllPads',
summary: 'list all the pads',
responseSchema: { padIDs: { type: 'array', items: { type: 'string' } } },
responseSchema: {padIDs: {type: 'array', items: {type: 'string'}}},
},
createDiffHTML: {
operationId: 'createDiffHTML',
@ -158,7 +158,7 @@ const resources = {
getText: {
operationId: 'getText',
summary: 'returns the text of a pad',
responseSchema: { text: { type: 'string' } },
responseSchema: {text: {type: 'string'}},
},
setText: {
operationId: 'setText',
@ -167,7 +167,7 @@ const resources = {
getHTML: {
operationId: 'getHTML',
summary: 'returns the text of a pad formatted as HTML',
responseSchema: { html: { type: 'string' } },
responseSchema: {html: {type: 'string'}},
},
setHTML: {
operationId: 'setHTML',
@ -176,12 +176,12 @@ const resources = {
getRevisionsCount: {
operationId: 'getRevisionsCount',
summary: 'returns the number of revisions of this pad',
responseSchema: { revisions: { type: 'integer' } },
responseSchema: {revisions: {type: 'integer'}},
},
getLastEdited: {
operationId: 'getLastEdited',
summary: 'returns the timestamp of the last revision of the pad',
responseSchema: { lastEdited: { type: 'integer' } },
responseSchema: {lastEdited: {type: 'integer'}},
},
delete: {
operationId: 'deletePad',
@ -190,7 +190,7 @@ const resources = {
getReadOnlyID: {
operationId: 'getReadOnlyID',
summary: 'returns the read only link of a pad',
responseSchema: { readOnlyID: { type: 'string' } },
responseSchema: {readOnlyID: {type: 'string'}},
},
setPublicStatus: {
operationId: 'setPublicStatus',
@ -199,22 +199,22 @@ const resources = {
getPublicStatus: {
operationId: 'getPublicStatus',
summary: 'return true of false',
responseSchema: { publicStatus: { type: 'boolean' } },
responseSchema: {publicStatus: {type: 'boolean'}},
},
authors: {
operationId: 'listAuthorsOfPad',
summary: 'returns an array of authors who contributed to this pad',
responseSchema: { authorIDs: { type: 'array', items: { type: 'string' } } },
responseSchema: {authorIDs: {type: 'array', items: {type: 'string'}}},
},
usersCount: {
operationId: 'padUsersCount',
summary: 'returns the number of user that are currently editing this pad',
responseSchema: { padUsersCount: { type: 'integer' } },
responseSchema: {padUsersCount: {type: 'integer'}},
},
users: {
operationId: 'padUsers',
summary: 'returns the list of users that are currently editing this pad',
responseSchema: { padUsers: { type: 'array', items: { $ref: '#/components/schemas/UserInfo' } } },
responseSchema: {padUsers: {type: 'array', items: {$ref: '#/components/schemas/UserInfo'}}},
},
sendClientsMessage: {
operationId: 'sendClientsMessage',
@ -227,13 +227,13 @@ const resources = {
getChatHistory: {
operationId: 'getChatHistory',
summary: 'returns the chat history',
responseSchema: { messages: { type: 'array', items: { $ref: '#/components/schemas/Message' } } },
responseSchema: {messages: {type: 'array', items: {$ref: '#/components/schemas/Message'}}},
},
// We need an operation that returns a Message so it can be picked up by the codegen :(
getChatHead: {
operationId: 'getChatHead',
summary: 'returns the chatHead (chat-message) of the pad',
responseSchema: { chatHead: { $ref: '#/components/schemas/Message' } },
responseSchema: {chatHead: {$ref: '#/components/schemas/Message'}},
},
appendChatMessage: {
operationId: 'appendChatMessage',
@ -384,10 +384,10 @@ const defaultResponseRefs = {
const operations = {};
for (const resource in resources) {
for (const action in resources[resource]) {
const { operationId, responseSchema, ...operation } = resources[resource][action];
const {operationId, responseSchema, ...operation} = resources[resource][action];
// add response objects
const responses = { ...defaultResponseRefs };
const responses = {...defaultResponseRefs};
if (responseSchema) {
responses[200] = cloneDeep(defaultResponses.Success);
responses[200].content['application/json'].schema.properties.data = {
@ -478,14 +478,14 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => {
},
},
},
security: [{ ApiKey: [] }],
security: [{ApiKey: []}],
};
// build operations
for (const funcName in apiHandler.version[version]) {
let operation = {};
if (operations[funcName]) {
operation = { ...operations[funcName] };
operation = {...operations[funcName]};
} else {
// console.warn(`No operation found for function: ${funcName}`);
operation = {
@ -497,7 +497,7 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => {
// set parameters
operation.parameters = operation.parameters || [];
for (const paramName of apiHandler.version[version][funcName]) {
operation.parameters.push({ $ref: `#/components/parameters/${paramName}` });
operation.parameters.push({$ref: `#/components/parameters/${paramName}`});
if (!definition.components.parameters[paramName]) {
definition.components.parameters[paramName] = {
name: paramName,
@ -533,7 +533,7 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => {
};
exports.expressCreateServer = (hookName, args, cb) => {
const { app } = args;
const {app} = args;
// create openapi-backend handlers for each api version under /api/{version}/*
for (const version in apiHandler.version) {
@ -550,7 +550,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
app.get(`${apiRoot}/openapi.json`, (req, res) => {
// For openapi definitions, wide CORS is probably fine
res.header('Access-Control-Allow-Origin', '*');
res.json({ ...definition, servers: [generateServerForApiVersion(apiRoot, req)] });
res.json({...definition, servers: [generateServerForApiVersion(apiRoot, req)]});
});
// serve latest openapi definition file under /api/openapi.json
@ -558,7 +558,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
if (isLatestAPIVersion) {
app.get(`/${style}/openapi.json`, (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.json({ ...definition, servers: [generateServerForApiVersion(apiRoot, req)] });
res.json({...definition, servers: [generateServerForApiVersion(apiRoot, req)]});
});
}
@ -586,7 +586,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
for (const funcName in apiHandler.version[version]) {
const handler = async (c, req, res) => {
// parse fields from request
const { header, params, query } = c.request;
const {header, params, query} = c.request;
// read form data if method was POST
let formData = {};
@ -602,7 +602,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
apiLogger.info(`REQUEST, v${version}:${funcName}, ${JSON.stringify(fields)}`);
// pass to api handler
let data = await apiHandler.handle(version, funcName, fields, req, res).catch((err) => {
const data = await apiHandler.handle(version, funcName, fields, req, res).catch((err) => {
// convert all errors to http errors
if (createHTTPError.isHttpError(err)) {
// pass http errors thrown by handler forward
@ -620,7 +620,7 @@ exports.expressCreateServer = (hookName, args, cb) => {
});
// return in common format
let response = { code: 0, message: 'ok', data: data || null };
const response = {code: 0, message: 'ok', data: data || null};
// log response
apiLogger.info(`RESPONSE, ${funcName}, ${JSON.stringify(response)}`);
@ -654,24 +654,24 @@ exports.expressCreateServer = (hookName, args, cb) => {
// https://github.com/ether/etherpad-lite/tree/master/doc/api/http_api.md#response-format
switch (res.statusCode) {
case 403: // forbidden
response = { code: 4, message: err.message, data: null };
response = {code: 4, message: err.message, data: null};
break;
case 401: // unauthorized (no or wrong api key)
response = { code: 4, message: err.message, data: null };
response = {code: 4, message: err.message, data: null};
break;
case 404: // not found (no such function)
response = { code: 3, message: err.message, data: null };
response = {code: 3, message: err.message, data: null};
break;
case 500: // server error (internal error)
response = { code: 2, message: err.message, data: null };
response = {code: 2, message: err.message, data: null};
break;
case 400: // bad request (wrong parameters)
// respond with 200 OK to keep old behavior and pass tests
res.statusCode = 200; // @TODO: this is bad api design
response = { code: 1, message: err.message, data: null };
response = {code: 1, message: err.message, data: null};
break;
default:
response = { code: 1, message: err.message, data: null };
response = {code: 1, message: err.message, data: null};
break;
}
}

View file

@ -1,13 +1,12 @@
var readOnlyManager = require("../../db/ReadOnlyManager");
var hasPadAccess = require("../../padaccess");
var exporthtml = require("../../utils/ExportHtml");
const readOnlyManager = require('../../db/ReadOnlyManager');
const hasPadAccess = require('../../padaccess');
const exporthtml = require('../../utils/ExportHtml');
exports.expressCreateServer = function (hook_name, args, cb) {
// serve read only pad
args.app.get('/ro/:id', async function(req, res) {
args.app.get('/ro/:id', async (req, res) => {
// translate the read only pad to a padId
let padId = await readOnlyManager.getPadId(req.params.id);
const padId = await readOnlyManager.getPadId(req.params.id);
if (padId == null) {
res.status(404).send('404 - Not Found');
return;
@ -18,9 +17,9 @@ exports.expressCreateServer = function (hook_name, args, cb) {
if (await hasPadAccess(req, res)) {
// render the html document
let html = await exporthtml.getPadHTMLDocument(padId, null);
const html = await exporthtml.getPadHTMLDocument(padId, null);
res.send(html);
}
});
return cb();
}
};

View file

@ -1,30 +1,29 @@
var padManager = require('../../db/PadManager');
var url = require('url');
const padManager = require('../../db/PadManager');
const url = require('url');
exports.expressCreateServer = function (hook_name, args, cb) {
// redirects browser to the pad's sanitized url if needed. otherwise, renders the html
args.app.param('pad', async function (req, res, next, padId) {
args.app.param('pad', async (req, res, next, padId) => {
// ensure the padname is valid and the url doesn't end with a /
if (!padManager.isValidPadId(padId) || /\/$/.test(req.url)) {
res.status(404).send('Such a padname is forbidden');
return;
}
let sanitizedPadId = await padManager.sanitizePadId(padId);
const sanitizedPadId = await padManager.sanitizePadId(padId);
if (sanitizedPadId === padId) {
// the pad id was fine, so just render it
next();
} else {
// the pad id was sanitized, so we redirect to the sanitized version
var real_url = sanitizedPadId;
let real_url = sanitizedPadId;
real_url = encodeURIComponent(real_url);
var query = url.parse(req.url).query;
if ( query ) real_url += '?' + query;
const query = url.parse(req.url).query;
if (query) real_url += `?${query}`;
res.header('Location', real_url);
res.status(302).send('You should be redirected to <a href="' + real_url + '">' + real_url + '</a>');
res.status(302).send(`You should be redirected to <a href="${real_url}">${real_url}</a>`);
}
});
return cb();
}
};

View file

@ -1,19 +1,19 @@
const express = require("../express");
const express = require('../express');
const proxyaddr = require('proxy-addr');
var settings = require('../../utils/Settings');
var socketio = require('socket.io');
var socketIORouter = require("../../handler/SocketIORouter");
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
const settings = require('../../utils/Settings');
const socketio = require('socket.io');
const socketIORouter = require('../../handler/SocketIORouter');
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
var padMessageHandler = require("../../handler/PadMessageHandler");
const padMessageHandler = require('../../handler/PadMessageHandler');
exports.expressCreateServer = function (hook_name, args, cb) {
//init socket.io and redirect all requests to the MessageHandler
// init socket.io and redirect all requests to the MessageHandler
// there shouldn't be a browser that isn't compatible to all
// transports in this list at once
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
var io = socketio({
transports: settings.socketTransportProtocols
const io = socketio({
transports: settings.socketTransportProtocols,
}).listen(args.server, {
/*
* Do not set the "io" cookie.
@ -61,17 +61,17 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// https://github.com/Automattic/socket.io/wiki/Migrating-to-1.0
// This debug logging environment is set in Settings.js
//minify socket.io javascript
// minify socket.io javascript
// Due to a shitty decision by the SocketIO team minification is
// no longer available, details available at:
// http://stackoverflow.com/questions/23981741/minify-socket-io-socket-io-js-with-1-0
// if(settings.minify) io.enable('browser client minification');
//Initalize the Socket.IO Router
// Initalize the Socket.IO Router
socketIORouter.setSocketIO(io);
socketIORouter.addComponent("pad", padMessageHandler);
socketIORouter.addComponent('pad', padMessageHandler);
hooks.callAll("socketio", {"app": args.app, "io": io, "server": args.server});
hooks.callAll('socketio', {app: args.app, io, server: args.server});
return cb();
}
};

View file

@ -1,83 +1,81 @@
var path = require('path');
var eejs = require('ep_etherpad-lite/node/eejs');
var toolbar = require("ep_etherpad-lite/node/utils/toolbar");
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
var settings = require('../../utils/Settings');
const path = require('path');
const eejs = require('ep_etherpad-lite/node/eejs');
const toolbar = require('ep_etherpad-lite/node/utils/toolbar');
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
const settings = require('../../utils/Settings');
const webaccess = require('./webaccess');
exports.expressCreateServer = function (hook_name, args, cb) {
// expose current stats
args.app.get('/stats', function(req, res) {
res.json(require('ep_etherpad-lite/node/stats').toJSON())
})
args.app.get('/stats', (req, res) => {
res.json(require('ep_etherpad-lite/node/stats').toJSON());
});
//serve index.html under /
args.app.get('/', function(req, res) {
// serve index.html under /
args.app.get('/', (req, res) => {
res.send(eejs.require('ep_etherpad-lite/templates/index.html', {req}));
});
//serve javascript.html
args.app.get('/javascript', function(req, res) {
// serve javascript.html
args.app.get('/javascript', (req, res) => {
res.send(eejs.require('ep_etherpad-lite/templates/javascript.html', {req}));
});
//serve robots.txt
args.app.get('/robots.txt', function(req, res) {
var filePath = path.join(settings.root, "src", "static", "skins", settings.skinName, "robots.txt");
res.sendFile(filePath, function(err) {
//there is no custom robots.txt, send the default robots.txt which dissallows all
if(err)
{
filePath = path.join(settings.root, "src", "static", "robots.txt");
// serve robots.txt
args.app.get('/robots.txt', (req, res) => {
let filePath = path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'robots.txt');
res.sendFile(filePath, (err) => {
// there is no custom robots.txt, send the default robots.txt which dissallows all
if (err) {
filePath = path.join(settings.root, 'src', 'static', 'robots.txt');
res.sendFile(filePath);
}
});
});
//serve pad.html under /p
args.app.get('/p/:pad', function(req, res, next) {
// serve pad.html under /p
args.app.get('/p/:pad', (req, res, next) => {
// The below might break for pads being rewritten
const isReadOnly =
req.url.indexOf("/p/r.") === 0 || !webaccess.userCanModify(req.params.pad, req);
req.url.indexOf('/p/r.') === 0 || !webaccess.userCanModify(req.params.pad, req);
hooks.callAll("padInitToolbar", {
toolbar: toolbar,
isReadOnly: isReadOnly
hooks.callAll('padInitToolbar', {
toolbar,
isReadOnly,
});
res.send(eejs.require("ep_etherpad-lite/templates/pad.html", {
req: req,
toolbar: toolbar,
isReadOnly: isReadOnly
res.send(eejs.require('ep_etherpad-lite/templates/pad.html', {
req,
toolbar,
isReadOnly,
}));
});
//serve timeslider.html under /p/$padname/timeslider
args.app.get('/p/:pad/timeslider', function(req, res, next) {
hooks.callAll("padInitToolbar", {
toolbar: toolbar
// serve timeslider.html under /p/$padname/timeslider
args.app.get('/p/:pad/timeslider', (req, res, next) => {
hooks.callAll('padInitToolbar', {
toolbar,
});
res.send(eejs.require("ep_etherpad-lite/templates/timeslider.html", {
req: req,
toolbar: toolbar
res.send(eejs.require('ep_etherpad-lite/templates/timeslider.html', {
req,
toolbar,
}));
});
//serve favicon.ico from all path levels except as a pad name
args.app.get( /\/favicon.ico$/, function(req, res) {
var filePath = path.join(settings.root, "src", "static", "skins", settings.skinName, "favicon.ico");
// serve favicon.ico from all path levels except as a pad name
args.app.get(/\/favicon.ico$/, (req, res) => {
let filePath = path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico');
res.sendFile(filePath, function(err) {
//there is no custom favicon, send the default favicon
if(err)
{
filePath = path.join(settings.root, "src", "static", "favicon.ico");
res.sendFile(filePath, (err) => {
// there is no custom favicon, send the default favicon
if (err) {
filePath = path.join(settings.root, 'src', 'static', 'favicon.ico');
res.sendFile(filePath);
}
});
});
return cb();
}
};

View file

@ -1,14 +1,13 @@
var minify = require('../../utils/Minify');
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugin_defs");
var CachingMiddleware = require('../../utils/caching_middleware');
var settings = require("../../utils/Settings");
var Yajsml = require('etherpad-yajsml');
var _ = require("underscore");
const minify = require('../../utils/Minify');
const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs');
const CachingMiddleware = require('../../utils/caching_middleware');
const settings = require('../../utils/Settings');
const Yajsml = require('etherpad-yajsml');
const _ = require('underscore');
exports.expressCreateServer = function (hook_name, args, cb) {
// Cache both minified and static.
var assetCache = new CachingMiddleware;
const assetCache = new CachingMiddleware();
args.app.all(/\/javascripts\/(.*)/, assetCache.handle);
// Minify will serve static files compressed (minify enabled). It also has
@ -18,43 +17,42 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// Setup middleware that will package JavaScript files served by minify for
// CommonJS loader on the client-side.
// Hostname "invalid.invalid" is a dummy value to allow parsing as a URI.
var jsServer = new (Yajsml.Server)({
rootPath: 'javascripts/src/'
, rootURI: 'http://invalid.invalid/static/js/'
, libraryPath: 'javascripts/lib/'
, libraryURI: 'http://invalid.invalid/static/plugins/'
, requestURIs: minify.requestURIs // Loop-back is causing problems, this is a workaround.
const jsServer = new (Yajsml.Server)({
rootPath: 'javascripts/src/',
rootURI: 'http://invalid.invalid/static/js/',
libraryPath: 'javascripts/lib/',
libraryURI: 'http://invalid.invalid/static/plugins/',
requestURIs: minify.requestURIs, // Loop-back is causing problems, this is a workaround.
});
var StaticAssociator = Yajsml.associators.StaticAssociator;
var associations =
const StaticAssociator = Yajsml.associators.StaticAssociator;
const associations =
Yajsml.associators.associationsForSimpleMapping(minify.tar);
var associator = new StaticAssociator(associations);
const associator = new StaticAssociator(associations);
jsServer.setAssociator(associator);
args.app.use(jsServer.handle.bind(jsServer));
// serve plugin definitions
// not very static, but served here so that client can do require("pluginfw/static/js/plugin-definitions.js");
args.app.get('/pluginfw/plugin-definitions.json', function (req, res, next) {
args.app.get('/pluginfw/plugin-definitions.json', (req, res, next) => {
const clientParts = _(plugins.parts)
.filter((part) => _(part).has('client_hooks'));
var clientParts = _(plugins.parts)
.filter(function(part){ return _(part).has('client_hooks') });
var clientPlugins = {};
const clientPlugins = {};
_(clientParts).chain()
.map(function(part){ return part.plugin })
.uniq()
.each(function(name){
clientPlugins[name] = _(plugins.plugins[name]).clone();
delete clientPlugins[name]['package'];
});
.map((part) => part.plugin)
.uniq()
.each((name) => {
clientPlugins[name] = _(plugins.plugins[name]).clone();
delete clientPlugins[name].package;
});
res.header("Content-Type","application/json; charset=utf-8");
res.write(JSON.stringify({"plugins": clientPlugins, "parts": clientParts}));
res.header('Content-Type', 'application/json; charset=utf-8');
res.write(JSON.stringify({plugins: clientPlugins, parts: clientParts}));
res.end();
});
return cb();
}
};

View file

@ -1,13 +1,13 @@
var path = require("path")
, npm = require("npm")
, fs = require("fs")
, util = require("util");
const path = require('path');
const npm = require('npm');
const fs = require('fs');
const util = require('util');
exports.expressCreateServer = function (hook_name, args, cb) {
args.app.get('/tests/frontend/specs_list.js', async function(req, res) {
let [coreTests, pluginTests] = await Promise.all([
args.app.get('/tests/frontend/specs_list.js', async (req, res) => {
const [coreTests, pluginTests] = await Promise.all([
exports.getCoreTests(),
exports.getPluginTests()
exports.getPluginTests(),
]);
// merge the two sets of results
@ -16,79 +16,77 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// Keep only *.js files
files = files.filter((f) => f.endsWith('.js'));
console.debug("Sent browser the following test specs:", files);
console.debug('Sent browser the following test specs:', files);
res.setHeader('content-type', 'text/javascript');
res.end("var specs_list = " + JSON.stringify(files) + ";\n");
res.end(`var specs_list = ${JSON.stringify(files)};\n`);
});
// path.join seems to normalize by default, but we'll just be explicit
var rootTestFolder = path.normalize(path.join(npm.root, "../tests/frontend/"));
const rootTestFolder = path.normalize(path.join(npm.root, '../tests/frontend/'));
var url2FilePath = function(url) {
var subPath = url.substr("/tests/frontend".length);
if (subPath == "") {
subPath = "index.html"
const url2FilePath = function (url) {
let subPath = url.substr('/tests/frontend'.length);
if (subPath == '') {
subPath = 'index.html';
}
subPath = subPath.split("?")[0];
subPath = subPath.split('?')[0];
var filePath = path.normalize(path.join(rootTestFolder, subPath));
let filePath = path.normalize(path.join(rootTestFolder, subPath));
// make sure we jail the paths to the test folder, otherwise serve index
if (filePath.indexOf(rootTestFolder) !== 0) {
filePath = path.join(rootTestFolder, "index.html");
filePath = path.join(rootTestFolder, 'index.html');
}
return filePath;
}
};
args.app.get('/tests/frontend/specs/*', function (req, res) {
var specFilePath = url2FilePath(req.url);
var specFileName = path.basename(specFilePath);
args.app.get('/tests/frontend/specs/*', (req, res) => {
const specFilePath = url2FilePath(req.url);
const specFileName = path.basename(specFilePath);
fs.readFile(specFilePath, function(err, content) {
fs.readFile(specFilePath, (err, content) => {
if (err) { return res.send(500); }
content = "describe(" + JSON.stringify(specFileName) + ", function(){ " + content + " });";
content = `describe(${JSON.stringify(specFileName)}, function(){ ${content} });`;
res.send(content);
});
});
args.app.get('/tests/frontend/*', function (req, res) {
var filePath = url2FilePath(req.url);
args.app.get('/tests/frontend/*', (req, res) => {
const filePath = url2FilePath(req.url);
res.sendFile(filePath);
});
args.app.get('/tests/frontend', function (req, res) {
args.app.get('/tests/frontend', (req, res) => {
res.redirect('/tests/frontend/index.html');
});
return cb();
}
};
const readdir = util.promisify(fs.readdir);
exports.getPluginTests = async function(callback) {
const moduleDir = "node_modules/";
const specPath = "/static/tests/frontend/specs/";
const staticDir = "/static/plugins/";
exports.getPluginTests = async function (callback) {
const moduleDir = 'node_modules/';
const specPath = '/static/tests/frontend/specs/';
const staticDir = '/static/plugins/';
let pluginSpecs = [];
const pluginSpecs = [];
let plugins = await readdir(moduleDir);
let promises = plugins
.map(plugin => [ plugin, moduleDir + plugin + specPath] )
.filter(([plugin, specDir]) => fs.existsSync(specDir)) // check plugin exists
.map(([plugin, specDir]) => {
return readdir(specDir)
.then(specFiles => specFiles.map(spec => {
pluginSpecs.push(staticDir + plugin + specPath + spec);
}));
});
const plugins = await readdir(moduleDir);
const promises = plugins
.map((plugin) => [plugin, moduleDir + plugin + specPath])
.filter(([plugin, specDir]) => fs.existsSync(specDir)) // check plugin exists
.map(([plugin, specDir]) => readdir(specDir)
.then((specFiles) => specFiles.map((spec) => {
pluginSpecs.push(staticDir + plugin + specPath + spec);
})));
return Promise.all(promises).then(() => pluginSpecs);
}
};
exports.getCoreTests = function() {
exports.getCoreTests = function () {
// get the core test specs
return readdir('tests/frontend/specs');
}
};

View file

@ -1,58 +1,58 @@
var languages = require('languages4translatewiki')
, fs = require('fs')
, path = require('path')
, _ = require('underscore')
, npm = require('npm')
, plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs.js').plugins
, semver = require('semver')
, existsSync = require('../utils/path_exists')
, settings = require('../utils/Settings')
const languages = require('languages4translatewiki');
const fs = require('fs');
const path = require('path');
const _ = require('underscore');
const npm = require('npm');
const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs.js').plugins;
const semver = require('semver');
const existsSync = require('../utils/path_exists');
const settings = require('../utils/Settings')
;
// returns all existing messages merged together and grouped by langcode
// {es: {"foo": "string"}, en:...}
function getAllLocales() {
var locales2paths = {};
const locales2paths = {};
// Puts the paths of all locale files contained in a given directory
// into `locales2paths` (files from various dirs are grouped by lang code)
// (only json files with valid language code as name)
function extractLangs(dir) {
if(!existsSync(dir)) return;
var stat = fs.lstatSync(dir);
if (!existsSync(dir)) return;
let stat = fs.lstatSync(dir);
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
fs.readdirSync(dir).forEach(function(file) {
fs.readdirSync(dir).forEach((file) => {
file = path.resolve(dir, file);
stat = fs.lstatSync(file);
if (stat.isDirectory() || stat.isSymbolicLink()) return;
var ext = path.extname(file)
, locale = path.basename(file, ext).toLowerCase();
const ext = path.extname(file);
const locale = path.basename(file, ext).toLowerCase();
if ((ext == '.json') && languages.isValid(locale)) {
if(!locales2paths[locale]) locales2paths[locale] = [];
if (!locales2paths[locale]) locales2paths[locale] = [];
locales2paths[locale].push(file);
}
});
}
//add core supported languages first
extractLangs(npm.root+"/ep_etherpad-lite/locales");
// add core supported languages first
extractLangs(`${npm.root}/ep_etherpad-lite/locales`);
//add plugins languages (if any)
for(var pluginName in plugins) extractLangs(path.join(npm.root, pluginName, 'locales'));
// add plugins languages (if any)
for (const pluginName in plugins) extractLangs(path.join(npm.root, pluginName, 'locales'));
// Build a locale index (merge all locale data other than user-supplied overrides)
var locales = {}
_.each (locales2paths, function(files, langcode) {
locales[langcode]={};
const locales = {};
_.each(locales2paths, (files, langcode) => {
locales[langcode] = {};
files.forEach(function(file) {
files.forEach((file) => {
let fileContents;
try {
fileContents = JSON.parse(fs.readFileSync(file,'utf8'));
fileContents = JSON.parse(fs.readFileSync(file, 'utf8'));
} catch (err) {
console.error(`failed to read JSON file ${file}: ${err}`);
throw err;
@ -64,17 +64,17 @@ function getAllLocales() {
// Add custom strings from settings.json
// Since this is user-supplied, we'll do some extra sanity checks
const wrongFormatErr = Error(
"customLocaleStrings in wrong format. See documentation " +
"for Customization for Administrators, under Localization.")
'customLocaleStrings in wrong format. See documentation ' +
'for Customization for Administrators, under Localization.');
if (settings.customLocaleStrings) {
if (typeof settings.customLocaleStrings !== "object") throw wrongFormatErr
_.each(settings.customLocaleStrings, function(overrides, langcode) {
if (typeof overrides !== "object") throw wrongFormatErr
_.each(overrides, function(localeString, key) {
if (typeof localeString !== "string") throw wrongFormatErr
locales[langcode][key] = localeString
})
})
if (typeof settings.customLocaleStrings !== 'object') throw wrongFormatErr;
_.each(settings.customLocaleStrings, (overrides, langcode) => {
if (typeof overrides !== 'object') throw wrongFormatErr;
_.each(overrides, (localeString, key) => {
if (typeof localeString !== 'string') throw wrongFormatErr;
locales[langcode][key] = localeString;
});
});
}
return locales;
@ -83,45 +83,44 @@ function getAllLocales() {
// returns a hash of all available languages availables with nativeName and direction
// e.g. { es: {nativeName: "español", direction: "ltr"}, ... }
function getAvailableLangs(locales) {
var result = {};
_.each(_.keys(locales), function(langcode) {
const result = {};
_.each(_.keys(locales), (langcode) => {
result[langcode] = languages.getLanguageInfo(langcode);
});
return result;
}
// returns locale index that will be served in /locales.json
var generateLocaleIndex = function (locales) {
var result = _.clone(locales) // keep English strings
_.each(_.keys(locales), function(langcode) {
if (langcode != 'en') result[langcode]='locales/'+langcode+'.json';
const generateLocaleIndex = function (locales) {
const result = _.clone(locales); // keep English strings
_.each(_.keys(locales), (langcode) => {
if (langcode != 'en') result[langcode] = `locales/${langcode}.json`;
});
return JSON.stringify(result);
}
};
exports.expressCreateServer = function(n, args, cb) {
//regenerate locales on server restart
var locales = getAllLocales();
var localeIndex = generateLocaleIndex(locales);
exports.expressCreateServer = function (n, args, cb) {
// regenerate locales on server restart
const locales = getAllLocales();
const localeIndex = generateLocaleIndex(locales);
exports.availableLangs = getAvailableLangs(locales);
args.app.get ('/locales/:locale', function(req, res) {
//works with /locale/en and /locale/en.json requests
var locale = req.params.locale.split('.')[0];
args.app.get('/locales/:locale', (req, res) => {
// works with /locale/en and /locale/en.json requests
const locale = req.params.locale.split('.')[0];
if (exports.availableLangs.hasOwnProperty(locale)) {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send('{"'+locale+'":'+JSON.stringify(locales[locale])+'}');
res.send(`{"${locale}":${JSON.stringify(locales[locale])}}`);
} else {
res.status(404).send('Language not available');
}
})
});
args.app.get('/locales.json', function(req, res) {
args.app.get('/locales.json', (req, res) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send(localeIndex);
})
});
return cb();
}
};