mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 06:03:34 +01:00
Merge branch 'develop'
This commit is contained in:
commit
65867eb895
41 changed files with 563 additions and 401 deletions
6
.github/workflows/backend-tests.yml
vendored
6
.github/workflows/backend-tests.yml
vendored
|
@ -30,9 +30,8 @@ jobs:
|
|||
- name: Install all dependencies and symlink for ep_etherpad-lite
|
||||
run: src/bin/installDeps.sh
|
||||
|
||||
# configures some settings and runs npm run test
|
||||
- name: Run the backend tests
|
||||
run: src/tests/frontend/travis/runnerBackend.sh
|
||||
run: cd src && npm test
|
||||
|
||||
withplugins:
|
||||
# run on pushes to any branch
|
||||
|
@ -84,6 +83,5 @@ jobs:
|
|||
- name: Install all dependencies and symlink for ep_etherpad-lite
|
||||
run: src/bin/installDeps.sh
|
||||
|
||||
# configures some settings and runs npm run test
|
||||
- name: Run the backend tests
|
||||
run: src/tests/frontend/travis/runnerBackend.sh
|
||||
run: cd src && npm test
|
||||
|
|
|
@ -64,7 +64,7 @@ jobs:
|
|||
- "src/bin/installDeps.sh"
|
||||
- "cd src && npm install && cd -"
|
||||
script:
|
||||
- "src/tests/frontend/travis/runnerBackend.sh"
|
||||
- "cd src && npm test"
|
||||
- name: "Test the Dockerfile"
|
||||
install:
|
||||
- "cd src && npm install && cd -"
|
||||
|
@ -107,7 +107,7 @@ jobs:
|
|||
- *install_plugins
|
||||
- "cd src && npm install && cd -"
|
||||
script:
|
||||
- "src/tests/frontend/travis/runnerBackend.sh"
|
||||
- "cd src && npm test"
|
||||
- name: "Test the Dockerfile"
|
||||
install:
|
||||
- "cd src && npm install && cd -"
|
||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,3 +1,15 @@
|
|||
# 1.8.9
|
||||
|
||||
### Notable fixes
|
||||
|
||||
* Fixed HTTP 400 error when importing via the UI.
|
||||
* Fixed "Error: spawn npm ENOENT" crash on startup in Windows.
|
||||
|
||||
### Notable enhancements
|
||||
|
||||
* Removed some unnecessary arrow key handling logic.
|
||||
* Dependency updates.
|
||||
|
||||
# 1.8.8
|
||||
|
||||
### Security patches
|
||||
|
|
25
Dockerfile
25
Dockerfile
|
@ -15,6 +15,22 @@ LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
|
|||
# ETHERPAD_PLUGINS="ep_codepad ep_author_neat"
|
||||
ARG ETHERPAD_PLUGINS=
|
||||
|
||||
# Control whether abiword will be installed, enabling exports to DOC/PDF/ODT formats.
|
||||
# By default, it is not installed.
|
||||
# If given any value, abiword will be installed.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# INSTALL_ABIWORD=true
|
||||
ARG INSTALL_ABIWORD=
|
||||
|
||||
# Control whether libreoffice will be installed, enabling exports to DOC/PDF/ODT formats.
|
||||
# By default, it is not installed.
|
||||
# If given any value, libreoffice will be installed.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# INSTALL_LIBREOFFICE=true
|
||||
ARG INSTALL_SOFFICE=
|
||||
|
||||
# By default, Etherpad container is built and run in "production" mode. This is
|
||||
# leaner (development dependencies are not installed) and runs faster (among
|
||||
# other things, assets are minified & compressed).
|
||||
|
@ -28,6 +44,13 @@ RUN useradd --uid 5001 --create-home etherpad
|
|||
|
||||
RUN mkdir /opt/etherpad-lite && chown etherpad:0 /opt/etherpad-lite
|
||||
|
||||
# install abiword for DOC/PDF/ODT export
|
||||
RUN [ -z "${INSTALL_ABIWORD}" ] || (apt update && apt -y install abiword && apt clean && rm -rf /var/lib/apt/lists/*)
|
||||
|
||||
# install libreoffice for DOC/PDF/ODT export
|
||||
# the mkdir is needed for configuration of openjdk-11-jre-headless, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
|
||||
RUN [ -z "${INSTALL_SOFFICE}" ] || (apt update && mkdir -p /usr/share/man/man1 && apt -y install libreoffice && apt clean && rm -rf /var/lib/apt/lists/*)
|
||||
|
||||
USER etherpad
|
||||
|
||||
WORKDIR /opt/etherpad-lite
|
||||
|
@ -51,4 +74,4 @@ COPY --chown=etherpad:0 ./settings.json.docker /opt/etherpad-lite/settings.json
|
|||
RUN chmod -R g=u .
|
||||
|
||||
EXPOSE 9001
|
||||
CMD ["node", "--experimental-worker", "node_modules/ep_etherpad-lite/node/server.js"]
|
||||
CMD ["node", "--experimental-worker", "src/node/server.js"]
|
||||
|
|
|
@ -66,7 +66,7 @@ Update to the latest version with `git pull origin`, then run
|
|||
|
||||
If cloning to a subdirectory within another project, you may need to do the following:
|
||||
|
||||
1. Start the server manually (e.g. `node/node_modules/ep_etherpad-lite/node/server.js`)
|
||||
1. Start the server manually (e.g. `node src/node/server.js`)
|
||||
2. Edit the db `filename` in `settings.json` to the relative directory with the file (e.g. `application/lib/etherpad-lite/var/dirty.db`)
|
||||
3. Add auto-generated files to the main project `.gitignore`
|
||||
|
||||
|
|
|
@ -29,6 +29,30 @@ The variable value has to be a space separated, double quoted list of plugin nam
|
|||
|
||||
Some plugins will need personalized settings. Just refer to the previous section, and include them in your custom `settings.json.docker`.
|
||||
|
||||
### Rebuilding including export functionality for DOC/PDF/ODT
|
||||
|
||||
If you want to be able to export your pads to DOC/PDF/ODT files, you can install
|
||||
either Abiword or Libreoffice via setting a build variable.
|
||||
|
||||
#### Via Abiword
|
||||
|
||||
For installing Abiword, set the `INSTALL_ABIWORD` build variable to any value.
|
||||
|
||||
Also, you will need to configure the path to the abiword executable
|
||||
via setting the `abiword` property in `<BASEDIR>/settings.json.docker` to
|
||||
`/usr/bin/abiword` or via setting the environment variable `ABIWORD` to
|
||||
`/usr/bin/abiword`.
|
||||
|
||||
#### Via Libreoffice
|
||||
|
||||
For installing Libreoffice instead, set the `INSTALL_SOFFICE` build variable
|
||||
to any value.
|
||||
|
||||
Also, you will need to configure the path to the libreoffice executable
|
||||
via setting the `soffice` property in `<BASEDIR>/settings.json.docker` to
|
||||
`/usr/bin/soffice` or via setting the environment variable `SOFFICE` to
|
||||
`/usr/bin/soffice`.
|
||||
|
||||
### Examples
|
||||
|
||||
Build a Docker image from the currently checked-out code:
|
||||
|
@ -168,8 +192,8 @@ For the editor container, you can also make it full width by adding `full-width-
|
|||
| `IMPORT_MAX_FILE_SIZE` | maximum allowed file size when importing a pad, in bytes. | `52428800` (50 MB) |
|
||||
| `IMPORT_EXPORT_MAX_REQ_PER_IP` | maximum number of import/export calls per IP. | `10` |
|
||||
| `IMPORT_EXPORT_RATE_LIMIT_WINDOW` | the call rate for import/export requests will be estimated in this time window (in milliseconds) | `90000` |
|
||||
| `COMMIT_RATE_LIMIT_DURATION` | duration of the rate limit window for commits by individual users/IPs (in seconds) | `1` |
|
||||
| `COMMIT_RATE_LIMIT_POINTS` | maximum number of changes per IP to allow during the rate limit window | `10` |
|
||||
| `COMMIT_RATE_LIMIT_DURATION` | duration of the rate limit window for commits by individual users/IPs (in seconds) | `1` |
|
||||
| `COMMIT_RATE_LIMIT_POINTS` | maximum number of changes per IP to allow during the rate limit window | `10` |
|
||||
| `SUPPRESS_ERRORS_IN_PAD_TEXT` | Should we suppress errors from being visible in the default Pad Text? | `false` |
|
||||
| `REQUIRE_SESSION` | If this option is enabled, a user must have a session to access pads. This effectively allows only group pads to be accessed. | `false` |
|
||||
| `EDIT_ONLY` | Users may edit pads but not create new ones. Pad creation is only via the API. This applies both to group pads and regular pads. | `false` |
|
||||
|
|
|
@ -7,7 +7,7 @@ fatal() { error "$@"; exit 1; }
|
|||
is_cmd() { command -v "$@" >/dev/null 2>&1; }
|
||||
|
||||
# Move to the folder where ep-lite is installed
|
||||
cd "$(dirname "$0")"/..
|
||||
cd "$(cd "${0%/*}" && pwd -P)/../.."
|
||||
|
||||
# Is wget installed?
|
||||
is_cmd wget || fatal "Please install wget"
|
||||
|
@ -54,7 +54,7 @@ rm -rf "$TMP_FOLDER"/src/node_modules/nodemailer/node_modules/mailcomposer/node_
|
|||
|
||||
log "create the zip..."
|
||||
cd "$TMP_FOLDER"
|
||||
zip -9 -r "$START_FOLDER"/etherpad-lite-win.zip ./*
|
||||
zip -9 -r "$START_FOLDER"/etherpad-lite-win.zip ./* -x var
|
||||
|
||||
log "clean up..."
|
||||
rm -rf "$TMP_FOLDER"
|
||||
|
|
|
@ -34,7 +34,6 @@ rm -rf src/node_modules
|
|||
src/bin/installDeps.sh "$@" || exit 1
|
||||
|
||||
#Move to the node folder and start
|
||||
echo "Started Etherpad..."
|
||||
echo "Starting Etherpad..."
|
||||
|
||||
SCRIPTPATH=$(pwd -P)
|
||||
node $(compute_node_args) "${SCRIPTPATH}/node_modules/ep_etherpad-lite/node/server.js" "$@"
|
||||
exec node $(compute_node_args) src/node/server.js "$@"
|
||||
|
|
|
@ -20,7 +20,7 @@ end script
|
|||
|
||||
script
|
||||
cd $EPHOME/
|
||||
exec su -s /bin/sh -c 'exec "$0" "$@"' $EPUSER -- node node_modules/ep_etherpad-lite/node/server.js \
|
||||
exec su -s /bin/sh -c 'exec "$0" "$@"' $EPUSER -- node src/node/server.js \
|
||||
>> $EPLOGS/access.log \
|
||||
2>> $EPLOGS/error.log
|
||||
echo "Etherpad is running on http://localhost:9001 - To change settings edit /opt/etherpad/settings.json"
|
||||
|
|
|
@ -16,4 +16,4 @@ echo "Open 'chrome://inspect' on Chrome to start debugging."
|
|||
|
||||
# Use 0.0.0.0 to allow external connections to the debugger
|
||||
# (ex: running Etherpad on a docker container). Use default port # (9229)
|
||||
node $(compute_node_args) --inspect=0.0.0.0:9229 node_modules/ep_etherpad-lite/node/server.js "$@"
|
||||
exec node $(compute_node_args) --inspect=0.0.0.0:9229 src/node/server.js "$@"
|
||||
|
|
6
src/bin/doc/package-lock.json
generated
6
src/bin/doc/package-lock.json
generated
|
@ -5,9 +5,9 @@
|
|||
"requires": true,
|
||||
"dependencies": {
|
||||
"marked": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
|
||||
"integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw=="
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
|
||||
"integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"node": ">=10.17.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"marked": "0.8.2"
|
||||
"marked": "1.1.1"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"optionalDependencies": {},
|
||||
|
|
|
@ -19,4 +19,4 @@ cd "${MY_DIR}/../.." || exit 1
|
|||
echo "Running directly, without checking/installing dependencies"
|
||||
|
||||
# run Etherpad main class
|
||||
node $(compute_node_args) "node_modules/ep_etherpad-lite/node/server.js" "$@"
|
||||
exec node $(compute_node_args) src/node/server.js "$@"
|
||||
|
|
|
@ -43,9 +43,8 @@ jobs:
|
|||
cd node_modules/${{github.event.repository.name}}
|
||||
npm ci
|
||||
|
||||
# configures some settings and runs npm run test
|
||||
- name: Run the backend tests
|
||||
run: src/tests/frontend/travis/runnerBackend.sh
|
||||
run: cd src && npm test
|
||||
|
||||
##ETHERPAD_NPM_V=1
|
||||
##ETHERPAD_NPM_V=2
|
||||
## NPM configuration automatically created using src/bin/plugins/updateAllPluginsScript.sh
|
||||
|
|
|
@ -6,8 +6,12 @@ process.on('unhandledRejection', (err) => { throw err; });
|
|||
|
||||
const fs = require('fs');
|
||||
const childProcess = require('child_process');
|
||||
const log4js = require('log4js');
|
||||
const path = require('path');
|
||||
const semver = require('semver');
|
||||
|
||||
log4js.replaceConsole();
|
||||
|
||||
/*
|
||||
|
||||
Usage
|
||||
|
@ -25,10 +29,80 @@ if (!release) {
|
|||
throw new Error('No release type included');
|
||||
}
|
||||
|
||||
const cwd = path.join(fs.realpathSync(__dirname), '../../');
|
||||
process.chdir(cwd);
|
||||
|
||||
// Run command capturing stdout. Trailing newlines are stripped (like the shell does).
|
||||
const runc =
|
||||
(cmd, opts = {}) => childProcess.execSync(cmd, {encoding: 'utf8', ...opts}).replace(/\n+$/, '');
|
||||
// Run command without capturing stdout.
|
||||
const run = (cmd, opts = {}) => childProcess.execSync(cmd, {stdio: 'inherit', ...opts});
|
||||
|
||||
const readJson = (filename) => JSON.parse(fs.readFileSync(filename, {encoding: 'utf8', flag: 'r'}));
|
||||
const writeJson = (filename, obj) => {
|
||||
let json = JSON.stringify(obj, null, 2);
|
||||
if (json !== '' && !json.endsWith('\n')) json += '\n';
|
||||
fs.writeFileSync(filename, json);
|
||||
};
|
||||
|
||||
const assertWorkDirClean = (opts = {}) => {
|
||||
opts.cwd = runc('git rev-parse --show-cdup', opts) || cwd;
|
||||
const m = runc('git diff-files --name-status', opts);
|
||||
if (m !== '') throw new Error(`modifications in working directory ${opts.cwd}:\n${m}`);
|
||||
const u = runc('git ls-files -o --exclude-standard', opts);
|
||||
if (u !== '') throw new Error(`untracked files in working directory ${opts.cwd}:\n${u}`);
|
||||
const s = runc('git diff-index --cached --name-status HEAD', opts);
|
||||
if (s !== '') throw new Error(`uncommitted changes in working directory ${opts.cwd}:\n${s}`);
|
||||
};
|
||||
|
||||
const assertBranchCheckedOut = (branch, opts = {}) => {
|
||||
const b = runc('git symbolic-ref HEAD', opts);
|
||||
if (b !== `refs/heads/${branch}`) {
|
||||
const d = opts.cwd ? path.resolve(cwd, opts.cwd) : cwd;
|
||||
throw new Error(`${branch} must be checked out (cwd: ${d})`);
|
||||
}
|
||||
};
|
||||
|
||||
const assertUpstreamOk = (branch, opts = {}) => {
|
||||
const upstream = runc(`git rev-parse --symbolic-full-name ${branch}@{u}`, opts);
|
||||
if (!(new RegExp(`^refs/remotes/[^/]+/${branch}`)).test(upstream)) {
|
||||
throw new Error(`${branch} should track origin/${branch}; see git branch --set-upstream-to`);
|
||||
}
|
||||
try {
|
||||
run(`git merge-base --is-ancestor ${branch} ${branch}@{u}`);
|
||||
} catch (err) {
|
||||
if (err.status !== 1) throw err;
|
||||
throw new Error(`${branch} is ahead of origin/${branch}; do you need to push?`);
|
||||
}
|
||||
};
|
||||
|
||||
const dirExists = (dir) => {
|
||||
try {
|
||||
return fs.statSync(dir).isDirectory();
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') throw err;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Sanity checks for Etherpad repo.
|
||||
assertWorkDirClean();
|
||||
assertBranchCheckedOut('develop');
|
||||
assertUpstreamOk('develop');
|
||||
assertUpstreamOk('master');
|
||||
|
||||
// Sanity checks for documentation repo.
|
||||
if (!dirExists('../ether.github.com')) {
|
||||
throw new Error('please clone documentation repo: ' +
|
||||
'(cd .. && git clone git@github.com:ether/ether.github.com.git)');
|
||||
}
|
||||
assertWorkDirClean({cwd: '../ether.github.com/'});
|
||||
assertBranchCheckedOut('master', {cwd: '../ether.github.com/'});
|
||||
assertUpstreamOk('master', {cwd: '../ether.github.com/'});
|
||||
|
||||
const changelog = fs.readFileSync('CHANGELOG.md', {encoding: 'utf8', flag: 'r'});
|
||||
let packageJson = fs.readFileSync('./src/package.json', {encoding: 'utf8', flag: 'r'});
|
||||
packageJson = JSON.parse(packageJson);
|
||||
const currentVersion = packageJson.version;
|
||||
const pkg = readJson('./src/package.json');
|
||||
const currentVersion = pkg.version;
|
||||
|
||||
const newVersion = semver.inc(currentVersion, release);
|
||||
if (!newVersion) {
|
||||
|
@ -36,40 +110,95 @@ if (!newVersion) {
|
|||
throw new Error('Unable to generate new version from input');
|
||||
}
|
||||
|
||||
const changelogIncludesVersion = changelog.indexOf(newVersion) !== -1;
|
||||
|
||||
if (!changelogIncludesVersion) {
|
||||
if (!changelog.startsWith(`# ${newVersion}\n`)) {
|
||||
throw new Error(`No changelog record for ${newVersion}, please create changelog record`);
|
||||
}
|
||||
|
||||
console.log('Okay looks good, lets create the package.json and package-lock.json');
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Done with sanity checks, now it's time to make changes.
|
||||
|
||||
packageJson.version = newVersion;
|
||||
try {
|
||||
console.log('Updating develop branch...');
|
||||
run('git pull --ff-only');
|
||||
|
||||
fs.writeFileSync('src/package.json', JSON.stringify(packageJson, null, 2));
|
||||
console.log(`Bumping ${release} version (to ${newVersion})...`);
|
||||
pkg.version = newVersion;
|
||||
|
||||
// run npm version `release` where release is patch, minor or major
|
||||
childProcess.execSync('npm install --package-lock-only', {cwd: 'src/'});
|
||||
// run npm install --package-lock-only <-- required???
|
||||
writeJson('./src/package.json', pkg);
|
||||
|
||||
childProcess.execSync(`git checkout -b release/${newVersion}`);
|
||||
childProcess.execSync('git add src/package.json');
|
||||
childProcess.execSync('git add src/package-lock.json');
|
||||
childProcess.execSync('git commit -m "bump version"');
|
||||
childProcess.execSync(`git push origin release/${newVersion}`);
|
||||
// run npm version `release` where release is patch, minor or major
|
||||
run('npm install --package-lock-only', {cwd: 'src/'});
|
||||
// run npm install --package-lock-only <-- required???
|
||||
|
||||
// Many users will be using the latest LTS version of npm, and the latest LTS version of npm uses
|
||||
// lockfileVersion 1. Enforce v1 so that users don't see a (benign) compatibility warning.
|
||||
if (readJson('./src/package-lock.json').lockfileVersion !== 1) {
|
||||
throw new Error('Please regenerate package-lock.json with npm v6.x.');
|
||||
}
|
||||
|
||||
childProcess.execSync('make docs');
|
||||
childProcess.execSync('git clone git@github.com:ether/ether.github.com.git');
|
||||
childProcess.execSync(`cp -R out/doc/ ether.github.com/doc/v${newVersion}`);
|
||||
run('git add src/package.json');
|
||||
run('git add src/package-lock.json');
|
||||
run('git commit -m "bump version"');
|
||||
console.log('Switching to master...');
|
||||
run('git checkout master');
|
||||
console.log('Updating master branch...');
|
||||
run('git pull --ff-only');
|
||||
console.log('Merging develop into master...');
|
||||
run('git merge --no-ff --no-edit develop');
|
||||
console.log(`Creating ${newVersion} tag...`);
|
||||
run(`git tag -s '${newVersion}' -m '${newVersion}'`);
|
||||
console.log('Switching back to develop...');
|
||||
run('git checkout develop');
|
||||
console.log('Merging master into develop...');
|
||||
run('git merge --no-ff --no-edit master');
|
||||
} catch (err) {
|
||||
console.error(err.toString());
|
||||
console.warn('Resetting repository...');
|
||||
console.warn('Resetting master...');
|
||||
run('git checkout -f master');
|
||||
run('git reset --hard @{u}');
|
||||
console.warn('Resetting develop...');
|
||||
run('git checkout -f develop');
|
||||
run('git reset --hard @{u}');
|
||||
console.warn(`Deleting ${newVersion} tag...`);
|
||||
run(`git rev-parse -q --verify refs/tags/'${newVersion}' >/dev/null || exit 0; ` +
|
||||
`git tag -d '${newVersion}'`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log('Once merged into master please run the following commands');
|
||||
console.log(`git tag -a ${newVersion} -m ${newVersion} && git push origin master`);
|
||||
console.log(`cd ether.github.com && git add . && git commit -m '${newVersion} docs'`);
|
||||
console.log('Build the windows zip');
|
||||
try {
|
||||
console.log('Building documentation...');
|
||||
run('make docs');
|
||||
console.log('Updating ether.github.com master branch...');
|
||||
run('git pull --ff-only', {cwd: '../ether.github.com/'});
|
||||
console.log('Committing documentation...');
|
||||
run(`cp -R out/doc/ ../ether.github.com/doc/v'${newVersion}'`);
|
||||
run(`rm -f latest && ln -s 'v${newVersion}' latest`, {cwd: '../ether.github.com/doc/'});
|
||||
run('git add .', {cwd: '../ether.github.com/'});
|
||||
run(`git commit -m '${newVersion} docs'`, {cwd: '../ether.github.com/'});
|
||||
} catch (err) {
|
||||
console.error(err.toString());
|
||||
console.warn('Resetting repository...');
|
||||
console.warn('Resetting master...');
|
||||
run('git checkout -f master', {cwd: '../ether.github.com/'});
|
||||
run('git reset --hard @{u}', {cwd: '../ether.github.com/'});
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log('Done.');
|
||||
console.log('Review the new commits and the new tag:');
|
||||
console.log(' git log --graph --date-order --boundary --oneline --decorate develop@{u}..develop');
|
||||
console.log(` git show '${newVersion}'`);
|
||||
console.log(' (cd ../ether.github.com && git show)');
|
||||
console.log('If everything looks good then push:');
|
||||
console.log(` git push origin master develop '${newVersion}'`);
|
||||
console.log(' (cd ../ether.github.com && git push)');
|
||||
console.log('Create a Windows build:');
|
||||
console.log(' bin/buildForWindows.sh');
|
||||
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
|
||||
`with 'master' as the target and the version is ${newVersion}. Include the windows ` +
|
||||
'zip as an asset');
|
||||
console.log(`Once the new docs are uploaded then modify the download
|
||||
link on etherpad.org and then pull master onto develop`);
|
||||
console.log('Once the new docs are uploaded then modify the download links (replace ' +
|
||||
`${currentVersion} with ${newVersion} on etherpad.org and then pull master onto ` +
|
||||
'develop)');
|
||||
console.log('Finally go public with an announcement via our comms channels :)');
|
||||
|
|
|
@ -32,5 +32,4 @@ src/bin/installDeps.sh "$@" || exit 1
|
|||
# Move to the node folder and start
|
||||
log "Starting Etherpad..."
|
||||
|
||||
SCRIPTPATH=$(pwd -P)
|
||||
exec node $(compute_node_args) "$SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js" "$@"
|
||||
exec node $(compute_node_args) src/node/server.js "$@"
|
||||
|
|
|
@ -84,7 +84,8 @@
|
|||
"name": "socketio",
|
||||
"hooks": {
|
||||
"expressCloseServer": "ep_etherpad-lite/node/hooks/express/socketio",
|
||||
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/socketio"
|
||||
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/socketio",
|
||||
"socketio": "ep_etherpad-lite/node/handler/PadMessageHandler"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -103,20 +103,16 @@ const doImport = async (req, res, padId) => {
|
|||
// locally wrapped Promise, since form.parse requires a callback
|
||||
let srcFile = await new Promise((resolve, reject) => {
|
||||
form.parse(req, (err, fields, files) => {
|
||||
if (err || files.file === undefined) {
|
||||
// the upload failed, stop at this point
|
||||
if (err) {
|
||||
console.warn(`Uploading Error: ${err.stack}`);
|
||||
}
|
||||
|
||||
if (err != null) {
|
||||
logger.warn(`Import failed due to form error: ${err.stack || err}`);
|
||||
// I hate doing indexOf here but I can't see anything to use...
|
||||
if (err && err.stack && err.stack.indexOf('maxFileSize') !== -1) {
|
||||
return reject(new ImportError('maxFileSize'));
|
||||
}
|
||||
|
||||
return reject(new ImportError('uploadFailed'));
|
||||
}
|
||||
if (!files.file) { // might not be a graceful fix but it works
|
||||
if (!files.file) {
|
||||
logger.warn('Import failed because form had no file');
|
||||
return reject(new ImportError('uploadFailed'));
|
||||
}
|
||||
resolve(files.file.path);
|
||||
|
@ -140,7 +136,7 @@ const doImport = async (req, res, padId) => {
|
|||
srcFile = path.join(path.dirname(srcFile), `${path.basename(srcFile, fileEnding)}.txt`);
|
||||
await fs.rename(oldSrcFile, srcFile);
|
||||
} else {
|
||||
console.warn('Not allowing unknown file type to be imported', fileEnding);
|
||||
logger.warn(`Not allowing unknown file type to be imported: ${fileEnding}`);
|
||||
throw new ImportError('uploadFailed');
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +184,7 @@ const doImport = async (req, res, padId) => {
|
|||
convertor.convertFile(srcFile, destFile, exportExtension, (err) => {
|
||||
// catch convert errors
|
||||
if (err) {
|
||||
console.warn('Converting Error:', err);
|
||||
logger.warn(`Converting Error: ${err.stack || err}`);
|
||||
return reject(new ImportError('convertFailed'));
|
||||
}
|
||||
resolve();
|
||||
|
@ -205,6 +201,7 @@ const doImport = async (req, res, padId) => {
|
|||
const isAscii = !Array.prototype.some.call(buf, (c) => (c > 240));
|
||||
|
||||
if (!isAscii) {
|
||||
logger.warn('Attempt to import non-ASCII file');
|
||||
throw new ImportError('uploadFailed');
|
||||
}
|
||||
}
|
||||
|
@ -230,8 +227,8 @@ const doImport = async (req, res, padId) => {
|
|||
if (importHandledByPlugin || useConvertor || fileIsHTML) {
|
||||
try {
|
||||
await importHtml.setPadHTML(pad, text);
|
||||
} catch (e) {
|
||||
logger.warn('Error importing, possibly caused by malformed HTML');
|
||||
} catch (err) {
|
||||
logger.warn(`Error importing, possibly caused by malformed HTML: ${err.stack || err}`);
|
||||
}
|
||||
} else {
|
||||
await pad.setText(text);
|
||||
|
|
|
@ -40,10 +40,14 @@ const nodeify = require('nodeify');
|
|||
const {RateLimiterMemory} = require('rate-limiter-flexible');
|
||||
const webaccess = require('../hooks/express/webaccess');
|
||||
|
||||
const rateLimiter = new RateLimiterMemory({
|
||||
points: settings.commitRateLimiting.points,
|
||||
duration: settings.commitRateLimiting.duration,
|
||||
});
|
||||
let rateLimiter;
|
||||
|
||||
exports.socketio = () => {
|
||||
// The rate limiter is created in this hook so that restarting the server resets the limiter. The
|
||||
// settings.commitRateLimiting object is passed directly to the rate limiter so that the limits
|
||||
// can be dynamically changed during runtime by modifying its properties.
|
||||
rateLimiter = new RateLimiterMemory(settings.commitRateLimiting);
|
||||
};
|
||||
|
||||
/**
|
||||
* A associative array that saves information about a session
|
||||
|
|
|
@ -10,15 +10,15 @@ const rateLimit = require('express-rate-limit');
|
|||
const securityManager = require('../../db/SecurityManager');
|
||||
const webaccess = require('./webaccess');
|
||||
|
||||
settings.importExportRateLimiting.onLimitReached = (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}`);
|
||||
};
|
||||
|
||||
const limiter = rateLimit(settings.importExportRateLimiting);
|
||||
|
||||
exports.expressCreateServer = (hookName, args, cb) => {
|
||||
settings.importExportRateLimiting.onLimitReached = (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}`);
|
||||
};
|
||||
// The rate limiter is created in this hook so that restarting the server resets the limiter.
|
||||
const limiter = rateLimit(settings.importExportRateLimiting);
|
||||
|
||||
// handle export requests
|
||||
args.app.use('/p/:pad/:rev?/export/:type', limiter);
|
||||
args.app.get('/p/:pad/:rev?/export/:type', (req, res, next) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const childProcess = require('child_process');
|
||||
const spawn = require('cross-spawn');
|
||||
const log4js = require('log4js');
|
||||
const path = require('path');
|
||||
const settings = require('./Settings');
|
||||
|
@ -28,14 +28,14 @@ const logLines = (readable, logLineFn) => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Similar to `util.promisify(childProcess.exec)`, except:
|
||||
* Similar to `util.promisify(child_rocess.exec)`, except:
|
||||
* - `cwd` defaults to the Etherpad root directory.
|
||||
* - PATH is prefixed with src/node_modules/.bin so that utilities from installed dependencies
|
||||
* (e.g., npm) are preferred over system utilities.
|
||||
* - Output is passed to logger callback functions by default. See below for details.
|
||||
*
|
||||
* @param args Array of command-line arguments, where `args[0]` is the command to run.
|
||||
* @param opts Optional options that will be passed to `childProcess.spawn()` with two extensions:
|
||||
* @param opts Optional options that will be passed to `child_process.spawn()` with two extensions:
|
||||
* - `stdoutLogger`: Callback that is called each time a line of text is written to stdout (utf8
|
||||
* is assumed). The line (without trailing newline) is passed as the only argument. If null,
|
||||
* stdout is not logged. If unset, defaults to no-op. Ignored if stdout is not a pipe.
|
||||
|
@ -48,7 +48,7 @@ module.exports = exports = (args, opts = {}) => {
|
|||
logger.debug(`Executing command: ${args.join(' ')}`);
|
||||
|
||||
const {stdoutLogger = () => {}, stderrLogger = () => {}} = opts;
|
||||
// Avoid confusing childProcess.spawn() with our extensions.
|
||||
// Avoid confusing child_process.spawn() with our extensions.
|
||||
opts = {...opts}; // Make a copy to avoid mutating the caller's copy.
|
||||
delete opts.stdoutLogger;
|
||||
delete opts.stderrLogger;
|
||||
|
@ -70,7 +70,7 @@ module.exports = exports = (args, opts = {}) => {
|
|||
// process's `exit` handler so that we get a useful stack trace.
|
||||
const procFailedErr = new Error(`Command exited non-zero: ${args.join(' ')}`);
|
||||
|
||||
const proc = childProcess.spawn(args[0], args.slice(1), {cwd: settings.root, ...opts, env});
|
||||
const proc = spawn(args[0], args.slice(1), {cwd: settings.root, ...opts, env});
|
||||
if (proc.stdout != null && stdoutLogger != null) logLines(proc.stdout, stdoutLogger);
|
||||
if (proc.stderr != null && stderrLogger != null) logLines(proc.stderr, stderrLogger);
|
||||
const p = new Promise((resolve, reject) => {
|
||||
|
|
118
src/package-lock.json
generated
118
src/package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ep_etherpad-lite",
|
||||
"version": "1.8.8",
|
||||
"version": "1.8.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1281,7 +1281,6 @@
|
|||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
|
@ -1292,7 +1291,6 @@
|
|||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
|
@ -2028,9 +2026,9 @@
|
|||
"integrity": "sha1-7Y8E6f0szsOgBVu20t/p2ZkS5+I="
|
||||
},
|
||||
"etherpad-yajsml": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/etherpad-yajsml/-/etherpad-yajsml-0.0.2.tgz",
|
||||
"integrity": "sha1-HCTSaLCUduY30EnN2xxt+McptG4="
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/etherpad-yajsml/-/etherpad-yajsml-0.0.4.tgz",
|
||||
"integrity": "sha512-rxpEOMZmv6DOCQeaDo6tztneaKF9ZxbLo/+hQcV+hn0lNrxJZ7MKIPD2pTWWnNLj6gFFfs6QQ67RfMNWIr3fSA=="
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
|
@ -2082,9 +2080,9 @@
|
|||
}
|
||||
},
|
||||
"express-rate-limit": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.1.tgz",
|
||||
"integrity": "sha512-puA1zcCx/quwWUOU6pT6daCt6t7SweD9wKChKhb+KSgFMKRwS81C224hiSAUANw/gnSHiwEhgozM/2ezEBZPeA=="
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.2.3.tgz",
|
||||
"integrity": "sha512-cjQH+oDrEPXxc569XvxhHC6QXqJiuBT6BhZ70X3bdAImcnHnTNMVuMAJaT0TXPoRiEErUrVPRcOTpZpM36VbOQ=="
|
||||
},
|
||||
"express-session": {
|
||||
"version": "1.17.1",
|
||||
|
@ -2245,9 +2243,9 @@
|
|||
}
|
||||
},
|
||||
"formidable": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
|
||||
"integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
|
||||
"integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q=="
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.1.2",
|
||||
|
@ -3737,9 +3735,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"npm": {
|
||||
"version": "6.14.8",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz",
|
||||
"integrity": "sha512-HBZVBMYs5blsj94GTeQZel7s9odVuuSUHy1+AlZh7rPVux1os2ashvEGLy/STNK7vUjbrCg5Kq9/GXisJgdf6A==",
|
||||
"version": "6.14.11",
|
||||
"resolved": "https://registry.npmjs.org/npm/-/npm-6.14.11.tgz",
|
||||
"integrity": "sha512-1Zh7LjuIoEhIyjkBflSSGzfjuPQwDlghNloppjruOH5bmj9midT9qcNT0tRUZRR04shU9ekrxNy9+UTBrqeBpQ==",
|
||||
"requires": {
|
||||
"JSONStream": "^1.3.5",
|
||||
"abbrev": "~1.1.1",
|
||||
|
@ -3778,7 +3776,7 @@
|
|||
"infer-owner": "^1.0.4",
|
||||
"inflight": "~1.0.6",
|
||||
"inherits": "^2.0.4",
|
||||
"ini": "^1.3.5",
|
||||
"ini": "^1.3.8",
|
||||
"init-package-json": "^1.10.3",
|
||||
"is-cidr": "^3.0.0",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
|
@ -3821,10 +3819,10 @@
|
|||
"npm-pick-manifest": "^3.0.2",
|
||||
"npm-profile": "^4.0.4",
|
||||
"npm-registry-fetch": "^4.0.7",
|
||||
"npm-user-validate": "~1.0.0",
|
||||
"npm-user-validate": "^1.0.1",
|
||||
"npmlog": "~4.1.2",
|
||||
"once": "~1.4.0",
|
||||
"opener": "^1.5.1",
|
||||
"opener": "^1.5.2",
|
||||
"osenv": "^0.1.5",
|
||||
"pacote": "^9.5.12",
|
||||
"path-is-inside": "~1.0.2",
|
||||
|
@ -3892,16 +3890,6 @@
|
|||
"humanize-ms": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "5.5.2",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"co": "^4.6.0",
|
||||
"fast-deep-equal": "^1.0.0",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"ansi-align": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
|
@ -4187,10 +4175,6 @@
|
|||
"mkdirp": "~0.5.0"
|
||||
}
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"bundled": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
|
@ -4579,10 +4563,6 @@
|
|||
"version": "1.3.0",
|
||||
"bundled": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true
|
||||
|
@ -4867,11 +4847,31 @@
|
|||
"bundled": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.5",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"ajv": "^5.3.0",
|
||||
"ajv": "^6.12.3",
|
||||
"har-schema": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"bundled": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"bundled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"has": {
|
||||
|
@ -4976,7 +4976,7 @@
|
|||
"bundled": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"version": "1.3.8",
|
||||
"bundled": true
|
||||
},
|
||||
"init-package-json": {
|
||||
|
@ -5114,10 +5114,6 @@
|
|||
"version": "0.2.3",
|
||||
"bundled": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"bundled": true
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"bundled": true
|
||||
|
@ -5688,7 +5684,7 @@
|
|||
}
|
||||
},
|
||||
"npm-user-validate": {
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
},
|
||||
"npmlog": {
|
||||
|
@ -5733,7 +5729,7 @@
|
|||
}
|
||||
},
|
||||
"opener": {
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"bundled": true
|
||||
},
|
||||
"os-homedir": {
|
||||
|
@ -6563,6 +6559,19 @@
|
|||
"xdg-basedir": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.0",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"url-parse-lax": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
|
@ -7086,8 +7095,7 @@
|
|||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
|
@ -7536,9 +7544,9 @@
|
|||
"integrity": "sha1-gRwwAxNoYTPvAAcSXjsO1wCXiBU="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.17.1",
|
||||
|
@ -7610,7 +7618,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
|
@ -7618,8 +7625,7 @@
|
|||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.3",
|
||||
|
@ -8292,9 +8298,9 @@
|
|||
}
|
||||
},
|
||||
"tinycon": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tinycon/-/tinycon-0.0.1.tgz",
|
||||
"integrity": "sha1-beEM1SGaHxIdmgokssEbP7JN/+0="
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/tinycon/-/tinycon-0.6.8.tgz",
|
||||
"integrity": "sha1-59oiPj7gy/nbeWP6M1aZuyF3enM="
|
||||
},
|
||||
"to-array": {
|
||||
"version": "0.1.4",
|
||||
|
|
|
@ -36,14 +36,15 @@
|
|||
"cheerio": "0.22.0",
|
||||
"clean-css": "4.2.3",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"ejs": "^3.1.6",
|
||||
"etherpad-require-kernel": "1.0.9",
|
||||
"etherpad-yajsml": "0.0.2",
|
||||
"etherpad-yajsml": "0.0.4",
|
||||
"express": "4.17.1",
|
||||
"express-rate-limit": "5.1.1",
|
||||
"express-rate-limit": "5.2.3",
|
||||
"express-session": "1.17.1",
|
||||
"find-root": "1.1.0",
|
||||
"formidable": "1.2.1",
|
||||
"formidable": "1.2.2",
|
||||
"http-errors": "1.8.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"jsonminify": "0.4.1",
|
||||
|
@ -53,7 +54,7 @@
|
|||
"measured-core": "1.51.1",
|
||||
"mime-types": "^2.1.27",
|
||||
"nodeify": "1.0.1",
|
||||
"npm": "6.14.8",
|
||||
"npm": "6.14.11",
|
||||
"openapi-backend": "2.4.1",
|
||||
"proxy-addr": "^2.0.6",
|
||||
"rate-limiter-flexible": "^2.1.4",
|
||||
|
@ -62,12 +63,12 @@
|
|||
"request": "2.88.2",
|
||||
"resolve": "1.19.0",
|
||||
"security": "1.0.0",
|
||||
"semver": "5.6.0",
|
||||
"semver": "5.7.1",
|
||||
"socket.io": "^2.4.1",
|
||||
"terser": "^4.7.0",
|
||||
"threads": "^1.4.0",
|
||||
"tiny-worker": "^2.3.0",
|
||||
"tinycon": "0.0.1",
|
||||
"tinycon": "0.6.8",
|
||||
"ueberdb2": "^1.2.5",
|
||||
"underscore": "1.12.0",
|
||||
"unorm": "1.4.1",
|
||||
|
@ -236,6 +237,6 @@
|
|||
"test": "mocha --timeout 120000 --recursive tests/backend/specs ../node_modules/ep_*/static/tests/backend/specs",
|
||||
"test-container": "mocha --timeout 5000 tests/container/specs/api"
|
||||
},
|
||||
"version": "1.8.8",
|
||||
"version": "1.8.9",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
|
|
@ -3197,28 +3197,6 @@ function Ace2Inner() {
|
|||
scroll.setScrollY(caretOffsetTop);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// scroll to viewport when user presses arrow keys and caret is out of the viewport
|
||||
if ((evt.which === 37 || evt.which === 38 || evt.which === 39 || evt.which === 40)) {
|
||||
// we use arrowKeyWasReleased to avoid triggering the animation when a key
|
||||
// is continuously pressed
|
||||
// this makes the scroll smooth
|
||||
if (!continuouslyPressingArrowKey(type)) {
|
||||
// the caret position is not synchronized with the rep.
|
||||
// For example, when an user presses arrow
|
||||
// We use getSelection() instead of rep to get the caret position.
|
||||
// This avoids errors like when down to scroll the pad without releasing the key.
|
||||
// When the key is released the rep is not
|
||||
// synchronized, so we don't get the right node where caret is.
|
||||
const selection = getSelection();
|
||||
|
||||
if (selection) {
|
||||
const arrowUp = evt.which === 38;
|
||||
const innerHeight = getInnerHeight();
|
||||
scroll.scrollWhenPressArrowKeys(arrowUp, rep, innerHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'keydown') {
|
||||
|
@ -3263,19 +3241,6 @@ function Ace2Inner() {
|
|||
};
|
||||
|
||||
let thisKeyDoesntTriggerNormalize = false;
|
||||
let arrowKeyWasReleased = true;
|
||||
const continuouslyPressingArrowKey = (type) => {
|
||||
let firstTimeKeyIsContinuouslyPressed = false;
|
||||
|
||||
if (type === 'keyup') {
|
||||
arrowKeyWasReleased = true;
|
||||
} else if (type === 'keydown' && arrowKeyWasReleased) {
|
||||
firstTimeKeyIsContinuouslyPressed = true;
|
||||
arrowKeyWasReleased = false;
|
||||
}
|
||||
|
||||
return !firstTimeKeyIsContinuouslyPressed;
|
||||
};
|
||||
|
||||
const doUndoRedo = (which) => {
|
||||
// precond: normalized DOM
|
||||
|
|
|
@ -42,7 +42,7 @@ const padimpexp = (() => {
|
|||
$('#importmessagefail').fadeOut('fast');
|
||||
};
|
||||
|
||||
const fileInputSubmit = (e) => {
|
||||
const fileInputSubmit = function (e) {
|
||||
e.preventDefault();
|
||||
$('#importmessagefail').fadeOut('fast');
|
||||
if (!window.confirm(html10n.get('pad.impexp.confirmimport'))) return;
|
||||
|
|
|
@ -45,6 +45,8 @@ exports.init = async function () {
|
|||
// Start the Etherpad server on a random unused port.
|
||||
settings.port = 0;
|
||||
settings.ip = 'localhost';
|
||||
settings.importExportRateLimiting = {max: 0};
|
||||
settings.commitRateLimiting = {duration: 0.001, points: 1e6};
|
||||
exports.httpServer = await server.start();
|
||||
exports.baseUrl = `http://localhost:${exports.httpServer.address().port}`;
|
||||
exports.logger.debug(`HTTP server at ${exports.baseUrl}`);
|
||||
|
|
|
@ -8,19 +8,21 @@
|
|||
|
||||
const common = require('../../common');
|
||||
const fs = require('fs');
|
||||
const settings = require('../../../../node/utils/Settings');
|
||||
const supertest = require('supertest');
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
let apiVersion = 1;
|
||||
const testPadId = makeid();
|
||||
|
||||
const endPoint = (point, version) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
describe('Connectivity For Character Encoding', function () {
|
||||
it('can connect', function (done) {
|
||||
this.timeout(250);
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
});
|
||||
|
@ -29,7 +31,7 @@ describe(__filename, function () {
|
|||
describe('API Versioning', function () {
|
||||
this.timeout(150);
|
||||
it('finds the version tag', function (done) {
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect((res) => {
|
||||
apiVersion = res.body.currentVersion;
|
||||
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||
|
@ -45,7 +47,7 @@ describe(__filename, function () {
|
|||
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343
|
||||
// If your APIKey is password you deserve to fail all tests anyway
|
||||
const permErrorURL = `/api/${apiVersion}/createPad?apikey=password&padID=test`;
|
||||
api.get(permErrorURL)
|
||||
agent.get(permErrorURL)
|
||||
.expect(401, done);
|
||||
});
|
||||
});
|
||||
|
@ -53,7 +55,7 @@ describe(__filename, function () {
|
|||
describe('createPad', function () {
|
||||
it('creates a new Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||
})
|
||||
|
@ -66,7 +68,7 @@ describe(__filename, function () {
|
|||
it('Sets the HTML of a Pad attempting to weird utf8 encoded content', function (done) {
|
||||
this.timeout(1000);
|
||||
fs.readFile('tests/backend/specs/api/emojis.html', 'utf8', (err, html) => {
|
||||
api.post(endPoint('setHTML'))
|
||||
agent.post(endPoint('setHTML'))
|
||||
.send({
|
||||
padID: testPadId,
|
||||
html,
|
||||
|
@ -83,7 +85,7 @@ describe(__filename, function () {
|
|||
describe('getHTML', function () {
|
||||
it('get the HTML of Pad with emojis', function (done) {
|
||||
this.timeout(400);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.html.indexOf('🇼') === -1) {
|
||||
throw new Error('Unable to get the HTML');
|
||||
|
@ -101,11 +103,6 @@ describe(__filename, function () {
|
|||
|
||||
*/
|
||||
|
||||
var endPoint = function (point, version) {
|
||||
version = version || apiVersion;
|
||||
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||
};
|
||||
|
||||
function makeid() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
const common = require('../../common');
|
||||
const settings = require('../../../../node/utils/Settings');
|
||||
const supertest = require('supertest');
|
||||
'use strict';
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
const common = require('../../common');
|
||||
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
let apiVersion = 1;
|
||||
let authorID = '';
|
||||
const padID = makeid();
|
||||
const timestamp = Date.now();
|
||||
|
||||
const endPoint = (point) => `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
describe('API Versioning', function () {
|
||||
it('errors if can not connect', function (done) {
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect((res) => {
|
||||
apiVersion = res.body.currentVersion;
|
||||
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||
|
@ -37,7 +41,7 @@ describe(__filename, function () {
|
|||
describe('createPad', function () {
|
||||
this.timeout(400);
|
||||
it('creates a new Pad', function (done) {
|
||||
api.get(`${endPoint('createPad')}&padID=${padID}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${padID}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||
})
|
||||
|
@ -49,9 +53,11 @@ describe(__filename, function () {
|
|||
describe('createAuthor', function () {
|
||||
this.timeout(100);
|
||||
it('Creates an author with a name set', function (done) {
|
||||
api.get(endPoint('createAuthor'))
|
||||
agent.get(endPoint('createAuthor'))
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0 || !res.body.data.authorID) throw new Error('Unable to create author');
|
||||
if (res.body.code !== 0 || !res.body.data.authorID) {
|
||||
throw new Error('Unable to create author');
|
||||
}
|
||||
authorID = res.body.data.authorID; // we will be this author for the rest of the tests
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -62,7 +68,8 @@ describe(__filename, function () {
|
|||
describe('appendChatMessage', function () {
|
||||
this.timeout(100);
|
||||
it('Adds a chat message to the pad', function (done) {
|
||||
api.get(`${endPoint('appendChatMessage')}&padID=${padID}&text=blalblalbha&authorID=${authorID}&time=${timestamp}`)
|
||||
agent.get(`${endPoint('appendChatMessage')}&padID=${padID}&text=blalblalbha` +
|
||||
`&authorID=${authorID}&time=${timestamp}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to create chat message');
|
||||
})
|
||||
|
@ -75,7 +82,7 @@ describe(__filename, function () {
|
|||
describe('getChatHead', function () {
|
||||
this.timeout(100);
|
||||
it('Gets the head of chat', function (done) {
|
||||
api.get(`${endPoint('getChatHead')}&padID=${padID}`)
|
||||
agent.get(`${endPoint('getChatHead')}&padID=${padID}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.chatHead !== 0) throw new Error('Chat Head Length is wrong');
|
||||
|
||||
|
@ -89,9 +96,11 @@ describe(__filename, function () {
|
|||
describe('getChatHistory', function () {
|
||||
this.timeout(40);
|
||||
it('Gets Chat History of a Pad', function (done) {
|
||||
api.get(`${endPoint('getChatHistory')}&padID=${padID}`)
|
||||
agent.get(`${endPoint('getChatHistory')}&padID=${padID}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.messages.length !== 1) throw new Error('Chat History Length is wrong');
|
||||
if (res.body.data.messages.length !== 1) {
|
||||
throw new Error('Chat History Length is wrong');
|
||||
}
|
||||
if (res.body.code !== 0) throw new Error('Unable to get chat history');
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -100,10 +109,6 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
|
||||
var endPoint = function (point) {
|
||||
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||
};
|
||||
|
||||
function makeid() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
*/
|
||||
|
||||
const common = require('../../common');
|
||||
const settings = require('../../../container/loadSettings.js').loadSettings();
|
||||
const supertest = require('supertest');
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
const apiVersion = 1;
|
||||
|
||||
const endPoint = (point, version) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
const testImports = {
|
||||
'malformed': {
|
||||
input: '<html><body><li>wtf</ul></body></html>',
|
||||
|
@ -226,6 +226,8 @@ const testImports = {
|
|||
};
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
Object.keys(testImports).forEach((testName) => {
|
||||
describe(testName, function () {
|
||||
const testPadId = makeid();
|
||||
|
@ -237,7 +239,7 @@ describe(__filename, function () {
|
|||
}
|
||||
it('createPad', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||
})
|
||||
|
@ -247,7 +249,8 @@ describe(__filename, function () {
|
|||
|
||||
it('setHTML', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('setHTML')}&padID=${testPadId}&html=${encodeURIComponent(test.input)}`)
|
||||
agent.get(`${endPoint('setHTML')}&padID=${testPadId}` +
|
||||
`&html=${encodeURIComponent(test.input)}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error(`Error:${testName}`);
|
||||
})
|
||||
|
@ -257,7 +260,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getHTML', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
const gotHtml = res.body.data.html;
|
||||
if (gotHtml !== test.wantHTML) {
|
||||
|
@ -281,7 +284,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getText', function (done) {
|
||||
this.timeout(100);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
const gotText = res.body.data.text;
|
||||
if (gotText !== test.wantText) {
|
||||
|
@ -306,12 +309,6 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
function endPoint(point, version) {
|
||||
version = version || apiVersion;
|
||||
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||
}
|
||||
|
||||
function makeid() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
|
|
@ -127,7 +127,7 @@ describe(__filename, function () {
|
|||
|
||||
|
||||
describe('Import/Export tests requiring AbiWord/LibreOffice', function () {
|
||||
this.timeout(60000);
|
||||
this.timeout(10000);
|
||||
|
||||
before(async function () {
|
||||
if ((!settings.abiword || settings.abiword.indexOf('/') === -1) &&
|
||||
|
@ -139,7 +139,6 @@ describe(__filename, function () {
|
|||
// For some reason word import does not work in testing..
|
||||
// TODO: fix support for .doc files..
|
||||
it('Tries to import .doc that uses soffice or abiword', async function () {
|
||||
this.timeout(10000);
|
||||
await agent.post(`/p/${testPadId}/import`)
|
||||
.attach('file', wordDoc, {filename: '/test.doc', contentType: 'application/msword'})
|
||||
.expect(200)
|
||||
|
@ -152,7 +151,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('exports DOC', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.get(`/p/${testPadId}/export/doc`)
|
||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||
.expect(200)
|
||||
|
@ -160,7 +158,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('Tries to import .docx that uses soffice or abiword', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.post(`/p/${testPadId}/import`)
|
||||
.attach('file', wordXDoc, {
|
||||
filename: '/test.docx',
|
||||
|
@ -177,7 +174,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('exports DOC from imported DOCX', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.get(`/p/${testPadId}/export/doc`)
|
||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||
.expect(200)
|
||||
|
@ -185,7 +181,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('Tries to import .pdf that uses soffice or abiword', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.post(`/p/${testPadId}/import`)
|
||||
.attach('file', pdfDoc, {filename: '/test.pdf', contentType: 'application/pdf'})
|
||||
.expect(200)
|
||||
|
@ -198,7 +193,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('exports PDF', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.get(`/p/${testPadId}/export/pdf`)
|
||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||
.expect(200)
|
||||
|
@ -206,7 +200,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('Tries to import .odt that uses soffice or abiword', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.post(`/p/${testPadId}/import`)
|
||||
.attach('file', odtDoc, {filename: '/test.odt', contentType: 'application/odt'})
|
||||
.expect(200)
|
||||
|
@ -219,7 +212,6 @@ describe(__filename, function () {
|
|||
});
|
||||
|
||||
it('exports ODT', async function () {
|
||||
this.timeout(3000);
|
||||
await agent.get(`/p/${testPadId}/export/odt`)
|
||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||
.expect(200)
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* Tests for the instance-level APIs
|
||||
*
|
||||
* Section "GLOBAL FUNCTIONS" in src/node/db/API.js
|
||||
*/
|
||||
const common = require('../../common');
|
||||
const settings = require('../../../../node/utils/Settings');
|
||||
const supertest = require('supertest');
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
const apiVersion = '1.2.14';
|
||||
|
||||
const endPoint = (point, version) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
describe('Connectivity for instance-level API tests', function () {
|
||||
it('can connect', function (done) {
|
||||
this.timeout(150);
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
});
|
||||
|
@ -25,20 +28,25 @@ describe(__filename, function () {
|
|||
describe('getStats', function () {
|
||||
it('Gets the stats of a running instance', function (done) {
|
||||
this.timeout(100);
|
||||
api.get(endPoint('getStats'))
|
||||
agent.get(endPoint('getStats'))
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('getStats() failed');
|
||||
|
||||
if (!(('totalPads' in res.body.data) && (typeof res.body.data.totalPads === 'number'))) {
|
||||
throw new Error(`Response to getStats() does not contain field totalPads, or it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
if (!('totalPads' in res.body.data && typeof res.body.data.totalPads === 'number')) {
|
||||
throw new Error('Response to getStats() does not contain field totalPads, or ' +
|
||||
`it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
}
|
||||
|
||||
if (!(('totalSessions' in res.body.data) && (typeof res.body.data.totalSessions === 'number'))) {
|
||||
throw new Error(`Response to getStats() does not contain field totalSessions, or it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
if (!('totalSessions' in res.body.data &&
|
||||
typeof res.body.data.totalSessions === 'number')) {
|
||||
throw new Error('Response to getStats() does not contain field totalSessions, or ' +
|
||||
`it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
}
|
||||
|
||||
if (!(('totalActivePads' in res.body.data) && (typeof res.body.data.totalActivePads === 'number'))) {
|
||||
throw new Error(`Response to getStats() does not contain field totalActivePads, or it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
if (!('totalActivePads' in res.body.data &&
|
||||
typeof res.body.data.totalActivePads === 'number')) {
|
||||
throw new Error('Response to getStats() does not contain field totalActivePads, or ' +
|
||||
`it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -46,8 +54,3 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
var endPoint = function (point, version) {
|
||||
version = version || apiVersion;
|
||||
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* ACHTUNG: there is a copied & modified version of this file in
|
||||
* <basedir>/src/tests/container/specs/api/pad.js
|
||||
|
@ -5,19 +7,19 @@
|
|||
* TODO: unify those two files, and merge in a single one.
|
||||
*/
|
||||
|
||||
const assert = require('assert').strict;
|
||||
const async = require('async');
|
||||
const common = require('../../common');
|
||||
const settings = require('../../../../node/utils/Settings');
|
||||
const supertest = require('supertest');
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
let apiVersion = 1;
|
||||
const testPadId = makeid();
|
||||
let lastEdited = '';
|
||||
const text = generateLongText();
|
||||
|
||||
const endPoint = (point, version) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
/*
|
||||
* Html document with nested lists of different types, to test its import and
|
||||
* verify it is exported back correctly
|
||||
|
@ -45,10 +47,12 @@ const ulSpaceHtml = '<!doctype html><html><body><ul class="bullet"> <li>one</li>
|
|||
const expectedSpaceHtml = '<!doctype html><html><body><ul class="bullet"><li>one</ul></body></html>';
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
describe('Connectivity', function () {
|
||||
it('can connect', function (done) {
|
||||
this.timeout(200);
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
});
|
||||
|
@ -57,7 +61,7 @@ describe(__filename, function () {
|
|||
describe('API Versioning', function () {
|
||||
it('finds the version tag', function (done) {
|
||||
this.timeout(150);
|
||||
api.get('/api/')
|
||||
agent.get('/api/')
|
||||
.expect((res) => {
|
||||
apiVersion = res.body.currentVersion;
|
||||
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||
|
@ -73,7 +77,7 @@ describe(__filename, function () {
|
|||
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343
|
||||
// If your APIKey is password you deserve to fail all tests anyway
|
||||
const permErrorURL = `/api/${apiVersion}/createPad?apikey=password&padID=test`;
|
||||
api.get(permErrorURL)
|
||||
agent.get(permErrorURL)
|
||||
.expect(401, done);
|
||||
});
|
||||
});
|
||||
|
@ -123,7 +127,7 @@ describe(__filename, function () {
|
|||
describe('deletePad', function () {
|
||||
it('deletes a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done); // @TODO: we shouldn't expect 200 here since the pad may not exist
|
||||
});
|
||||
|
@ -132,7 +136,7 @@ describe(__filename, function () {
|
|||
describe('createPad', function () {
|
||||
it('creates a new Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||
})
|
||||
|
@ -144,7 +148,7 @@ describe(__filename, function () {
|
|||
describe('getRevisionsCount', function () {
|
||||
it('gets revision count of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to get Revision Count');
|
||||
if (res.body.data.revisions !== 0) throw new Error('Incorrect Revision Count');
|
||||
|
@ -157,10 +161,12 @@ describe(__filename, function () {
|
|||
describe('getSavedRevisionsCount', function () {
|
||||
it('gets saved revisions count of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to get Saved Revisions Count');
|
||||
if (res.body.data.savedRevisions !== 0) throw new Error('Incorrect Saved Revisions Count');
|
||||
if (res.body.data.savedRevisions !== 0) {
|
||||
throw new Error('Incorrect Saved Revisions Count');
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -170,10 +176,10 @@ describe(__filename, function () {
|
|||
describe('listSavedRevisions', function () {
|
||||
it('gets saved revision list of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to get Saved Revisions List');
|
||||
if (!res.body.data.savedRevisions.equals([])) throw new Error('Incorrect Saved Revisions List');
|
||||
assert.deepEqual(res.body.data.savedRevisions, []);
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -183,7 +189,7 @@ describe(__filename, function () {
|
|||
describe('getHTML', function () {
|
||||
it('get the HTML of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.html.length <= 1) throw new Error('Unable to get the HTML');
|
||||
})
|
||||
|
@ -195,7 +201,7 @@ describe(__filename, function () {
|
|||
describe('listAllPads', function () {
|
||||
it('list all pads', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(endPoint('listAllPads'))
|
||||
agent.get(endPoint('listAllPads'))
|
||||
.expect((res) => {
|
||||
if (res.body.data.padIDs.includes(testPadId) !== true) {
|
||||
throw new Error('Unable to find pad in pad list');
|
||||
|
@ -209,7 +215,7 @@ describe(__filename, function () {
|
|||
describe('deletePad', function () {
|
||||
it('deletes a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Deletion failed');
|
||||
})
|
||||
|
@ -221,7 +227,7 @@ describe(__filename, function () {
|
|||
describe('listAllPads', function () {
|
||||
it('list all pads', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(endPoint('listAllPads'))
|
||||
agent.get(endPoint('listAllPads'))
|
||||
.expect((res) => {
|
||||
if (res.body.data.padIDs.includes(testPadId) !== false) {
|
||||
throw new Error('Test pad should not be in pads list');
|
||||
|
@ -235,7 +241,7 @@ describe(__filename, function () {
|
|||
describe('getHTML', function () {
|
||||
it('get the HTML of a Pad -- Should return a failure', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 1) throw new Error('Pad deletion failed');
|
||||
})
|
||||
|
@ -247,7 +253,7 @@ describe(__filename, function () {
|
|||
describe('createPad', function () {
|
||||
it('creates a new Pad with text', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('createPad')}&padID=${testPadId}&text=testText`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${testPadId}&text=testText`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Creation failed');
|
||||
})
|
||||
|
@ -259,7 +265,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('gets the Pad text and expect it to be testText with \n which is a line break', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.text !== 'testText\n') throw new Error('Pad Creation with text');
|
||||
})
|
||||
|
@ -271,7 +277,7 @@ describe(__filename, function () {
|
|||
describe('setText', function () {
|
||||
it('creates a new Pad with text', function (done) {
|
||||
this.timeout(200);
|
||||
api.post(endPoint('setText'))
|
||||
agent.post(endPoint('setText'))
|
||||
.send({
|
||||
padID: testPadId,
|
||||
text: 'testTextTwo',
|
||||
|
@ -287,7 +293,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('gets the Pad text', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.text !== 'testTextTwo\n') throw new Error('Setting Text');
|
||||
})
|
||||
|
@ -299,7 +305,7 @@ describe(__filename, function () {
|
|||
describe('getRevisionsCount', function () {
|
||||
it('gets Revision Count of a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.revisions !== 1) throw new Error('Unable to get text revision count');
|
||||
})
|
||||
|
@ -311,7 +317,7 @@ describe(__filename, function () {
|
|||
describe('saveRevision', function () {
|
||||
it('saves Revision', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('saveRevision')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('saveRevision')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to save Revision');
|
||||
})
|
||||
|
@ -323,10 +329,12 @@ describe(__filename, function () {
|
|||
describe('getSavedRevisionsCount', function () {
|
||||
it('gets saved revisions count of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to get Saved Revisions Count');
|
||||
if (res.body.data.savedRevisions !== 1) throw new Error('Incorrect Saved Revisions Count');
|
||||
if (res.body.data.savedRevisions !== 1) {
|
||||
throw new Error('Incorrect Saved Revisions Count');
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -336,10 +344,10 @@ describe(__filename, function () {
|
|||
describe('listSavedRevisions', function () {
|
||||
it('gets saved revision list of Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Unable to get Saved Revisions List');
|
||||
if (!res.body.data.savedRevisions.equals([1])) throw new Error('Incorrect Saved Revisions List');
|
||||
assert.deepEqual(res.body.data.savedRevisions, [1]);
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -348,7 +356,7 @@ describe(__filename, function () {
|
|||
describe('padUsersCount', function () {
|
||||
it('gets User Count of a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('padUsersCount')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('padUsersCount')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.padUsersCount !== 0) throw new Error('Incorrect Pad User count');
|
||||
})
|
||||
|
@ -360,7 +368,7 @@ describe(__filename, function () {
|
|||
describe('getReadOnlyID', function () {
|
||||
it('Gets the Read Only ID of a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getReadOnlyID')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getReadOnlyID')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (!res.body.data.readOnlyID) throw new Error('No Read Only ID for Pad');
|
||||
})
|
||||
|
@ -372,9 +380,11 @@ describe(__filename, function () {
|
|||
describe('listAuthorsOfPad', function () {
|
||||
it('Get Authors of the Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('listAuthorsOfPad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('listAuthorsOfPad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.authorIDs.length !== 0) throw new Error('# of Authors of pad is not 0');
|
||||
if (res.body.data.authorIDs.length !== 0) {
|
||||
throw new Error('# of Authors of pad is not 0');
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -384,7 +394,7 @@ describe(__filename, function () {
|
|||
describe('getLastEdited', function () {
|
||||
it('Get When Pad was left Edited', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (!res.body.data.lastEdited) {
|
||||
throw new Error('# of Authors of pad is not 0');
|
||||
|
@ -400,7 +410,7 @@ describe(__filename, function () {
|
|||
describe('setText', function () {
|
||||
it('creates a new Pad with text', function (done) {
|
||||
this.timeout(200);
|
||||
api.post(endPoint('setText'))
|
||||
agent.post(endPoint('setText'))
|
||||
.send({
|
||||
padID: testPadId,
|
||||
text: 'testTextTwo',
|
||||
|
@ -416,7 +426,7 @@ describe(__filename, function () {
|
|||
describe('getLastEdited', function () {
|
||||
it('Get When Pad was left Edited', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.lastEdited <= lastEdited) {
|
||||
throw new Error('Editing A Pad is not updating when it was last edited');
|
||||
|
@ -430,7 +440,7 @@ describe(__filename, function () {
|
|||
describe('padUsers', function () {
|
||||
it('gets User Count of a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('padUsers')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('padUsers')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.padUsers.length !== 0) throw new Error('Incorrect Pad Users');
|
||||
})
|
||||
|
@ -442,7 +452,7 @@ describe(__filename, function () {
|
|||
describe('deletePad', function () {
|
||||
it('deletes a Pad', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('deletePad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Deletion failed');
|
||||
})
|
||||
|
@ -451,14 +461,13 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
|
||||
const originalPadId = testPadId;
|
||||
const newPadId = makeid();
|
||||
const copiedPadId = makeid();
|
||||
|
||||
describe('createPad', function () {
|
||||
it('creates a new Pad with text', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Creation failed');
|
||||
})
|
||||
|
@ -470,7 +479,7 @@ describe(__filename, function () {
|
|||
describe('setText', function () {
|
||||
it('Sets text on a pad Id', function (done) {
|
||||
this.timeout(150);
|
||||
api.post(`${endPoint('setText')}&padID=${testPadId}`)
|
||||
agent.post(`${endPoint('setText')}&padID=${testPadId}`)
|
||||
.field({text})
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Set Text failed');
|
||||
|
@ -483,7 +492,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('Gets text on a pad Id', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Get Text failed');
|
||||
if (res.body.data.text !== `${text}\n`) throw new Error('Pad Text not set properly');
|
||||
|
@ -496,7 +505,7 @@ describe(__filename, function () {
|
|||
describe('setText', function () {
|
||||
it('Sets text on a pad Id including an explicit newline', function (done) {
|
||||
this.timeout(200);
|
||||
api.post(`${endPoint('setText')}&padID=${testPadId}`)
|
||||
agent.post(`${endPoint('setText')}&padID=${testPadId}`)
|
||||
.field({text: `${text}\n`})
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Set Text failed');
|
||||
|
@ -509,7 +518,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it("Gets text on a pad Id and doesn't have an excess newline", function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Get Text failed');
|
||||
if (res.body.data.text !== `${text}\n`) throw new Error('Pad Text not set properly');
|
||||
|
@ -522,7 +531,7 @@ describe(__filename, function () {
|
|||
describe('getLastEdited', function () {
|
||||
it('Gets when pad was last edited', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.lastEdited === 0) throw new Error('Get Last Edited Failed');
|
||||
})
|
||||
|
@ -534,7 +543,7 @@ describe(__filename, function () {
|
|||
describe('movePad', function () {
|
||||
it('Move a Pad to a different Pad ID', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('movePad')}&sourceID=${testPadId}&destinationID=${newPadId}&force=true`)
|
||||
agent.get(`${endPoint('movePad')}&sourceID=${testPadId}&destinationID=${newPadId}&force=true`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Moving Pad Failed');
|
||||
})
|
||||
|
@ -546,7 +555,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('Gets text on a pad Id', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${newPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${newPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.text !== `${text}\n`) throw new Error('Pad Get Text failed');
|
||||
})
|
||||
|
@ -558,7 +567,8 @@ describe(__filename, function () {
|
|||
describe('movePad', function () {
|
||||
it('Move a Pad to a different Pad ID', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('movePad')}&sourceID=${newPadId}&destinationID=${testPadId}&force=false`)
|
||||
agent.get(`${endPoint('movePad')}&sourceID=${newPadId}&destinationID=${testPadId}` +
|
||||
'&force=false')
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Moving Pad Failed');
|
||||
})
|
||||
|
@ -570,7 +580,7 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('Gets text on a pad Id', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.data.text !== `${text}\n`) throw new Error('Pad Get Text failed');
|
||||
})
|
||||
|
@ -582,7 +592,7 @@ describe(__filename, function () {
|
|||
describe('getLastEdited', function () {
|
||||
it('Gets when pad was last edited', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.lastEdited === 0) throw new Error('Get Last Edited Failed');
|
||||
})
|
||||
|
@ -594,7 +604,7 @@ describe(__filename, function () {
|
|||
describe('appendText', function () {
|
||||
it('Append text to a pad Id', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('appendText', '1.2.13')}&padID=${testPadId}&text=hello`)
|
||||
agent.get(`${endPoint('appendText', '1.2.13')}&padID=${testPadId}&text=hello`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Append Text failed');
|
||||
})
|
||||
|
@ -606,10 +616,12 @@ describe(__filename, function () {
|
|||
describe('getText', function () {
|
||||
it('Gets text on a pad Id', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Pad Get Text failed');
|
||||
if (res.body.data.text !== `${text}hello\n`) throw new Error('Pad Text not set properly');
|
||||
if (res.body.data.text !== `${text}hello\n`) {
|
||||
throw new Error('Pad Text not set properly');
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -621,13 +633,15 @@ describe(__filename, function () {
|
|||
it('Sets the HTML of a Pad attempting to pass ugly HTML', function (done) {
|
||||
this.timeout(200);
|
||||
const html = '<div><b>Hello HTML</title></head></div>';
|
||||
api.post(endPoint('setHTML'))
|
||||
agent.post(endPoint('setHTML'))
|
||||
.send({
|
||||
padID: testPadId,
|
||||
html,
|
||||
})
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error("Crappy HTML Can't be Imported[we weren't able to sanitize it']");
|
||||
if (res.body.code !== 0) {
|
||||
throw new Error("Crappy HTML Can't be Imported[we weren't able to sanitize it']");
|
||||
}
|
||||
})
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, done);
|
||||
|
@ -637,7 +651,7 @@ describe(__filename, function () {
|
|||
describe('setHTML', function () {
|
||||
it('Sets the HTML of a Pad with complex nested lists of different types', function (done) {
|
||||
this.timeout(200);
|
||||
api.post(endPoint('setHTML'))
|
||||
agent.post(endPoint('setHTML'))
|
||||
.send({
|
||||
padID: testPadId,
|
||||
html: ulHtml,
|
||||
|
@ -653,7 +667,7 @@ describe(__filename, function () {
|
|||
describe('getHTML', function () {
|
||||
it('Gets back the HTML of a Pad with complex nested lists of different types', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase();
|
||||
|
||||
|
@ -677,7 +691,7 @@ describe(__filename, function () {
|
|||
describe('setHTML', function () {
|
||||
it('Sets the HTML of a Pad with white space between list items', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('setHTML')}&padID=${testPadId}&html=${ulSpaceHtml}`)
|
||||
agent.get(`${endPoint('setHTML')}&padID=${testPadId}&html=${ulSpaceHtml}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('List HTML cant be imported');
|
||||
})
|
||||
|
@ -689,7 +703,7 @@ describe(__filename, function () {
|
|||
describe('getHTML', function () {
|
||||
it('Gets back the HTML of a Pad with complex nested lists of different types', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||
.expect((res) => {
|
||||
const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase();
|
||||
if (receivedHtml !== expectedSpaceHtml) {
|
||||
|
@ -716,7 +730,7 @@ describe(__filename, function () {
|
|||
async.map(
|
||||
badUrlChars,
|
||||
(badUrlChar, cb) => {
|
||||
api.get(`${endPoint('createPad')}&padID=${badUrlChar}`)
|
||||
agent.get(`${endPoint('createPad')}&padID=${badUrlChar}`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 1) throw new Error('Pad with bad characters was created');
|
||||
})
|
||||
|
@ -730,7 +744,8 @@ describe(__filename, function () {
|
|||
describe('copyPad', function () {
|
||||
it('copies the content of a existent pad', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('copyPad')}&sourceID=${testPadId}&destinationID=${copiedPadId}&force=true`)
|
||||
agent.get(`${endPoint('copyPad')}&sourceID=${testPadId}&destinationID=${copiedPadId}` +
|
||||
'&force=true')
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Copy Pad Failed');
|
||||
})
|
||||
|
@ -747,13 +762,14 @@ describe(__filename, function () {
|
|||
createNewPadWithHtml(sourcePadId, ulHtml, done);
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(async function () {
|
||||
newPad = makeid();
|
||||
});
|
||||
|
||||
it('returns a successful response', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&destinationID=${newPad}&force=false`)
|
||||
agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` +
|
||||
`&destinationID=${newPad}&force=false`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Copy Pad Without History Failed');
|
||||
})
|
||||
|
@ -764,14 +780,16 @@ describe(__filename, function () {
|
|||
// this test validates if the source pad's text and attributes are kept
|
||||
it('creates a new pad with the same content as the source pad', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&destinationID=${newPad}&force=false`)
|
||||
agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` +
|
||||
`&destinationID=${newPad}&force=false`)
|
||||
.expect((res) => {
|
||||
if (res.body.code !== 0) throw new Error('Copy Pad Without History Failed');
|
||||
})
|
||||
.end(() => {
|
||||
api.get(`${endPoint('getHTML')}&padID=${newPad}`)
|
||||
agent.get(`${endPoint('getHTML')}&padID=${newPad}`)
|
||||
.expect((res) => {
|
||||
const receivedHtml = res.body.data.html.replace('<br><br></body>', '</body>').toLowerCase();
|
||||
const receivedHtml =
|
||||
res.body.data.html.replace('<br><br></body>', '</body>').toLowerCase();
|
||||
|
||||
if (receivedHtml !== expectedHtml) {
|
||||
throw new Error(`HTML received from export is not the one we were expecting.
|
||||
|
@ -794,7 +812,8 @@ describe(__filename, function () {
|
|||
const padWithNonExistentGroup = `notExistentGroup$${padId}`;
|
||||
it('throws an error', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&destinationID=${padWithNonExistentGroup}&force=true`)
|
||||
agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&` +
|
||||
`destinationID=${padWithNonExistentGroup}&force=true`)
|
||||
.expect((res) => {
|
||||
// code 1, it means an error has happened
|
||||
if (res.body.code !== 1) throw new Error('It should report an error');
|
||||
|
@ -813,7 +832,8 @@ describe(__filename, function () {
|
|||
context('and force is false', function () {
|
||||
it('throws an error', function (done) {
|
||||
this.timeout(150);
|
||||
api.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&destinationID=${padIdExistent}&force=false`)
|
||||
agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` +
|
||||
`&destinationID=${padIdExistent}&force=false`)
|
||||
.expect((res) => {
|
||||
// code 1, it means an error has happened
|
||||
if (res.body.code !== 1) throw new Error('It should report an error');
|
||||
|
@ -825,10 +845,13 @@ describe(__filename, function () {
|
|||
context('and force is true', function () {
|
||||
it('returns a successful response', function (done) {
|
||||
this.timeout(200);
|
||||
api.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}&destinationID=${padIdExistent}&force=true`)
|
||||
agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` +
|
||||
`&destinationID=${padIdExistent}&force=true`)
|
||||
.expect((res) => {
|
||||
// code 1, it means an error has happened
|
||||
if (res.body.code !== 0) throw new Error('Copy pad without history with force true failed');
|
||||
if (res.body.code !== 0) {
|
||||
throw new Error('Copy pad without history with force true failed');
|
||||
}
|
||||
})
|
||||
.expect(200, done);
|
||||
});
|
||||
|
@ -842,10 +865,10 @@ describe(__filename, function () {
|
|||
|
||||
*/
|
||||
|
||||
var createNewPadWithHtml = function (padId, html, cb) {
|
||||
api.get(`${endPoint('createPad')}&padID=${padId}`)
|
||||
const createNewPadWithHtml = (padId, html, cb) => {
|
||||
agent.get(`${endPoint('createPad')}&padID=${padId}`)
|
||||
.end(() => {
|
||||
api.post(endPoint('setHTML'))
|
||||
agent.post(endPoint('setHTML'))
|
||||
.send({
|
||||
padID: padId,
|
||||
html,
|
||||
|
@ -854,11 +877,6 @@ var createNewPadWithHtml = function (padId, html, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
var endPoint = function (point, version) {
|
||||
version = version || apiVersion;
|
||||
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||
};
|
||||
|
||||
function makeid() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
@ -878,22 +896,3 @@ function generateLongText() {
|
|||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// Need this to compare arrays (listSavedRevisions test)
|
||||
Array.prototype.equals = function (array) {
|
||||
// if the other array is a falsy value, return
|
||||
if (!array) return false;
|
||||
// compare lengths - can save a lot of time
|
||||
if (this.length != array.length) return false;
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
// Check if we have nested arrays
|
||||
if (this[i] instanceof Array && array[i] instanceof Array) {
|
||||
// recurse into the nested arrays
|
||||
if (!this[i].equals(array[i])) return false;
|
||||
} else if (this[i] != array[i]) {
|
||||
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert').strict;
|
||||
const common = require('../../common');
|
||||
const settings = require('../../../../node/utils/Settings');
|
||||
const supertest = require('supertest');
|
||||
|
||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||
|
||||
let agent;
|
||||
const apiKey = common.apiKey;
|
||||
let apiVersion = 1;
|
||||
let groupID = '';
|
||||
|
@ -12,11 +11,15 @@ let authorID = '';
|
|||
let sessionID = '';
|
||||
let padID = makeid();
|
||||
|
||||
const endPoint = (point) => `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||
|
||||
describe(__filename, function () {
|
||||
before(async function () { agent = await common.init(); });
|
||||
|
||||
describe('API Versioning', function () {
|
||||
it('errors if can not connect', async function () {
|
||||
this.timeout(200);
|
||||
await api.get('/api/')
|
||||
await agent.get('/api/')
|
||||
.expect(200)
|
||||
.expect((res) => {
|
||||
assert(res.body.currentVersion);
|
||||
|
@ -58,7 +61,7 @@ describe(__filename, function () {
|
|||
describe('API: Group creation and deletion', function () {
|
||||
it('createGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(endPoint('createGroup'))
|
||||
await agent.get(endPoint('createGroup'))
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -70,7 +73,7 @@ describe(__filename, function () {
|
|||
|
||||
it('listSessionsOfGroup for empty group', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -81,7 +84,7 @@ describe(__filename, function () {
|
|||
|
||||
it('deleteGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('deleteGroup')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('deleteGroup')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -91,7 +94,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createGroupIfNotExistsFor', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createGroupIfNotExistsFor')}&groupMapper=management`)
|
||||
await agent.get(`${endPoint('createGroupIfNotExistsFor')}&groupMapper=management`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -104,7 +107,7 @@ describe(__filename, function () {
|
|||
// Creates a group, creates 2 sessions, 2 pads and then deletes the group.
|
||||
it('createGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(endPoint('createGroup'))
|
||||
await agent.get(endPoint('createGroup'))
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -116,7 +119,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createAuthor', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(endPoint('createAuthor'))
|
||||
await agent.get(endPoint('createAuthor'))
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -128,8 +131,8 @@ describe(__filename, function () {
|
|||
|
||||
it('createSession', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createSession')
|
||||
}&authorID=${authorID}&groupID=${groupID}&validUntil=999999999999`)
|
||||
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` +
|
||||
'&validUntil=999999999999')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -141,8 +144,8 @@ describe(__filename, function () {
|
|||
|
||||
it('createSession', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createSession')
|
||||
}&authorID=${authorID}&groupID=${groupID}&validUntil=999999999999`)
|
||||
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` +
|
||||
'&validUntil=999999999999')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -154,7 +157,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createGroupPad', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x1234567`)
|
||||
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x1234567`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -164,7 +167,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createGroupPad', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x12345678`)
|
||||
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x12345678`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -174,7 +177,7 @@ describe(__filename, function () {
|
|||
|
||||
it('deleteGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('deleteGroup')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('deleteGroup')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -187,7 +190,7 @@ describe(__filename, function () {
|
|||
describe('API: Author creation', function () {
|
||||
it('createGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(endPoint('createGroup'))
|
||||
await agent.get(endPoint('createGroup'))
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -199,7 +202,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createAuthor', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(endPoint('createAuthor'))
|
||||
await agent.get(endPoint('createAuthor'))
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -210,7 +213,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createAuthor with name', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createAuthor')}&name=john`)
|
||||
await agent.get(`${endPoint('createAuthor')}&name=john`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -222,7 +225,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createAuthorIfNotExistsFor', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createAuthorIfNotExistsFor')}&authorMapper=chris`)
|
||||
await agent.get(`${endPoint('createAuthorIfNotExistsFor')}&authorMapper=chris`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -233,7 +236,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getAuthorName', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('getAuthorName')}&authorID=${authorID}`)
|
||||
await agent.get(`${endPoint('getAuthorName')}&authorID=${authorID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -246,8 +249,8 @@ describe(__filename, function () {
|
|||
describe('API: Sessions', function () {
|
||||
it('createSession', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createSession')
|
||||
}&authorID=${authorID}&groupID=${groupID}&validUntil=999999999999`)
|
||||
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` +
|
||||
'&validUntil=999999999999')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -259,7 +262,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getSessionInfo', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||
await agent.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -272,7 +275,7 @@ describe(__filename, function () {
|
|||
|
||||
it('listSessionsOfGroup', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -283,7 +286,7 @@ describe(__filename, function () {
|
|||
|
||||
it('deleteSession', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('deleteSession')}&sessionID=${sessionID}`)
|
||||
await agent.get(`${endPoint('deleteSession')}&sessionID=${sessionID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -293,7 +296,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getSessionInfo of deleted session', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||
await agent.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -305,7 +308,7 @@ describe(__filename, function () {
|
|||
describe('API: Group pad management', function () {
|
||||
it('listPads', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -316,7 +319,7 @@ describe(__filename, function () {
|
|||
|
||||
it('createGroupPad', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=${padID}`)
|
||||
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=${padID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -327,7 +330,7 @@ describe(__filename, function () {
|
|||
|
||||
it('listPads after creating a group pad', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||
await agent.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -340,7 +343,7 @@ describe(__filename, function () {
|
|||
describe('API: Pad security', function () {
|
||||
it('getPublicStatus', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||
await agent.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -351,7 +354,7 @@ describe(__filename, function () {
|
|||
|
||||
it('setPublicStatus', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('setPublicStatus')}&padID=${padID}&publicStatus=true`)
|
||||
await agent.get(`${endPoint('setPublicStatus')}&padID=${padID}&publicStatus=true`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -361,7 +364,7 @@ describe(__filename, function () {
|
|||
|
||||
it('getPublicStatus after changing public status', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||
await agent.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -378,7 +381,7 @@ describe(__filename, function () {
|
|||
describe('API: Misc', function () {
|
||||
it('listPadsOfAuthor', async function () {
|
||||
this.timeout(100);
|
||||
await api.get(`${endPoint('listPadsOfAuthor')}&authorID=${authorID}`)
|
||||
await agent.get(`${endPoint('listPadsOfAuthor')}&authorID=${authorID}`)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect((res) => {
|
||||
|
@ -389,11 +392,6 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
const endPoint = function (point) {
|
||||
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||
};
|
||||
|
||||
function makeid() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* caching_middleware is responsible for serving everything under path `/javascripts/`
|
||||
* That includes packages as defined in `src/node/utils/tar.json` and probably also plugin code
|
||||
|
@ -6,7 +8,6 @@
|
|||
|
||||
const common = require('../common');
|
||||
const assert = require('assert').strict;
|
||||
const url = require('url');
|
||||
const queryString = require('querystring');
|
||||
const settings = require('../../../node/utils/Settings');
|
||||
|
||||
|
@ -23,7 +24,7 @@ let agent;
|
|||
*/
|
||||
function isPlaintextResponse(fileContent, resource) {
|
||||
// callback=require.define&v=1234
|
||||
const query = url.parse(resource).query;
|
||||
const query = (new URL(resource, 'http://localhost')).search.slice(1);
|
||||
// require.define
|
||||
const jsonp = queryString.parse(query).callback;
|
||||
|
||||
|
|
|
@ -44,14 +44,14 @@ describe('select formatting buttons when selection has style applied', function
|
|||
|
||||
const testIfFormattingButtonIsDeselected = function (style) {
|
||||
it(`deselects the ${style} button`, function (done) {
|
||||
this.timeout(50);
|
||||
this.timeout(100);
|
||||
helper.waitFor(() => isButtonSelected(style) === false).done(done);
|
||||
});
|
||||
};
|
||||
|
||||
const testIfFormattingButtonIsSelected = function (style) {
|
||||
it(`selects the ${style} button`, function (done) {
|
||||
this.timeout(50);
|
||||
this.timeout(100);
|
||||
helper.waitFor(() => isButtonSelected(style)).done(done);
|
||||
});
|
||||
};
|
||||
|
@ -131,7 +131,7 @@ describe('select formatting buttons when selection has style applied', function
|
|||
|
||||
context('when user applies a style and the selection does not change', function () {
|
||||
it('selects the style button', async function () {
|
||||
this.timeout(50);
|
||||
this.timeout(100);
|
||||
const style = STYLES[0]; // italic
|
||||
applyStyleOnLine(style, FIRST_LINE);
|
||||
await helper.waitForPromise(() => isButtonSelected(style) === true);
|
||||
|
|
|
@ -14,7 +14,7 @@ MY_DIR=$(try cd "${0%/*}" && try pwd -P) || exit 1
|
|||
try cd "${MY_DIR}/../../../.."
|
||||
|
||||
log "Assuming src/bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js --experimental-worker "${@}" &
|
||||
node src/node/server.js --experimental-worker "${@}" &
|
||||
ep_pid=$!
|
||||
|
||||
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||
|
|
|
@ -14,7 +14,7 @@ MY_DIR=$(try cd "${0%/*}" && try pwd -P) || exit 1
|
|||
try cd "${MY_DIR}/../../../.."
|
||||
|
||||
log "Assuming src/bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js --experimental-worker "${@}" &
|
||||
node src/node/server.js --experimental-worker "${@}" &
|
||||
ep_pid=$!
|
||||
|
||||
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||
|
|
|
@ -17,8 +17,9 @@ s!"max":[^,]*!"max": 100!
|
|||
s!"points":[^,]*!"points": 1000!
|
||||
' settings.json.template >settings.json
|
||||
|
||||
log "Deprecation notice: runnerBackend.sh - Please use: cd src && npm test"
|
||||
log "Assuming src/bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js "${@}" &
|
||||
node src/node/server.js "${@}" &
|
||||
ep_pid=$!
|
||||
|
||||
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||
|
|
|
@ -17,7 +17,7 @@ s!"points":[^,]*!"points": 1000!
|
|||
' settings.json.template >settings.json
|
||||
|
||||
log "Assuming src/bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js "${@}" >/dev/null &
|
||||
node src/node/server.js "${@}" >/dev/null &
|
||||
ep_pid=$!
|
||||
|
||||
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<system.webServer>
|
||||
|
||||
<handlers>
|
||||
<add name="iisnode" path="node_modules/ep_etherpad-lite/node/server.js" verb="*" modules="iisnode" />
|
||||
<add name="iisnode" path="src/node/server.js" verb="*" modules="iisnode" />
|
||||
</handlers>
|
||||
|
||||
<rewrite>
|
||||
|
@ -10,7 +10,7 @@
|
|||
<!-- uncomment this section to enable debugging
|
||||
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
|
||||
<match url="iisnode"/>
|
||||
<action type="Rewrite" url="node_modules/ep_etherpad-lite/node/iisnode" />
|
||||
<action type="Rewrite" url="src/node/iisnode" />
|
||||
</rule>
|
||||
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
|
||||
<match url="^server.js\/debug[\/]?" />
|
||||
|
@ -23,7 +23,7 @@
|
|||
<conditions>
|
||||
<add input="{{REQUEST_FILENAME}}" matchType="IsFile" negate="True"/>
|
||||
</conditions>
|
||||
<action type="Rewrite" url="node_modules/ep_etherpad-lite/node/server.js" />
|
||||
<action type="Rewrite" url="src/node/server.js" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
|
10
start.bat
10
start.bat
|
@ -1 +1,11 @@
|
|||
@echo off
|
||||
REM Windows and symlinks do not get along with each other, so on Windows
|
||||
REM `node_modules\ep_etherpad-lite` is sometimes a full copy of `src` not a
|
||||
REM symlink to `src`. If it is a copy, Node.js sees `src\foo.js` and
|
||||
REM `node_modules\ep_etherpad-lite\foo.js` as two independent modules with
|
||||
REM independent state, when they should be treated as the same file. To work
|
||||
REM around this, everything must consistently use either `src` or
|
||||
REM `node_modules\ep_etherpad-lite` on Windows. Because some plugins access
|
||||
REM Etherpad internals via `require('ep_etherpad-lite/foo')`,
|
||||
REM `node_modules\ep_etherpad-lite` is used here.
|
||||
node node_modules\ep_etherpad-lite\node\server.js
|
||||
|
|
Loading…
Reference in a new issue