Skip to content

Commit 26e12ff

Browse files
JohnMcLearclaude
andcommitted
fix(6194): correct API param + document compactPad in http_api docs
The 1.3.1 entry in APIHandler registered `['padID', 'authorId']`, but `API.compactPad` takes `(padID, keepRevisions)` and the CLI sends a `keepRevisions` query param. APIHandler.handle dispatches by URL field name, so the previous wiring silently dropped `keepRevisions` and never ran the keep-last branch over HTTP. - Register `['padID', 'keepRevisions']` so the handler forwards the CLI/HTTP arg into the API function. - Add HTTP-level dispatch tests that hit `/api/1.3.1/compactPad` with and without `keepRevisions`. The direct `api.compactPad()` tests bypass the handler and would have missed this regression. - Document compactPad in `doc/api/http_api.md` and `http_api.adoc`, and bump the documented latest version from 1.3.0 to 1.3.1 to match `latestApiVersion`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7cebf85 commit 26e12ff

4 files changed

Lines changed: 73 additions & 3 deletions

File tree

doc/api/http_api.adoc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Portal submits content into new blog post
6565
=== Usage
6666

6767
==== API version
68-
The latest version is `1.3.0`
68+
The latest version is `1.3.1`
6969

7070
The current version can be queried via /api.
7171

@@ -588,6 +588,22 @@ _Example returns:_
588588
* `{code: 0, message:"ok", data: null}`
589589
* `{code: 1, message:"padID does not exist", data: null}`
590590

591+
==== compactPad(padID, [keepRevisions])
592+
* API >= 1.3.1
593+
594+
collapses the pad's revision history to reclaim database space (issue #6194). Wraps the same `Cleanup` helper that powers the admin-settings UI, so admins can trigger compaction over the public API or via `bin/compactPad` without going through the admin UI.
595+
596+
When `keepRevisions` is omitted (or null), all history is collapsed into a single base revision that reproduces the current pad text — equivalent to a freshly-imported pad. When set to a positive integer N, the pad keeps only its last N revisions.
597+
598+
Pad text and chat are preserved in both modes. Saved-revision bookmarks are cleared. *This operation is destructive — export the pad first via `getEtherpad` if you need a backup.*
599+
600+
_Example returns:_
601+
602+
* `{code: 0, message:"ok", data: {ok: true, mode: "all"}}`
603+
* `{code: 0, message:"ok", data: {ok: true, mode: "keepLast", keepRevisions: 50}}`
604+
* `{code: 1, message:"padID does not exist", data: null}`
605+
* `{code: 1, message:"keepRevisions must be a non-negative integer", data: null}`
606+
591607
==== getReadOnlyID(padID)
592608
* API >= 1
593609

doc/api/http_api.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Portal submits content into new blog post
9898
## Usage
9999

100100
### API version
101-
The latest version is `1.3.0`
101+
The latest version is `1.3.1`
102102

103103
The current version can be queried via /api.
104104

@@ -619,6 +619,21 @@ moves a pad. If force is true and the destination pad exists, it will be overwri
619619
* `{code: 0, message:"ok", data: null}`
620620
* `{code: 1, message:"padID does not exist", data: null}`
621621

622+
#### compactPad(padID, [keepRevisions])
623+
* API >= 1.3.1
624+
625+
collapses the pad's revision history to reclaim database space (issue #6194). Wraps the same `Cleanup` helper that powers the admin-settings UI, so admins can trigger compaction over the public API or via `bin/compactPad` without going through the admin UI.
626+
627+
When `keepRevisions` is omitted (or null), all history is collapsed into a single base revision that reproduces the current pad text — equivalent to a freshly-imported pad. When set to a positive integer N, the pad keeps only its last N revisions.
628+
629+
Pad text and chat are preserved in both modes. Saved-revision bookmarks are cleared. **This operation is destructive — export the pad first via `getEtherpad` if you need a backup.**
630+
631+
*Example returns:*
632+
* `{code: 0, message:"ok", data: {ok: true, mode: "all"}}`
633+
* `{code: 0, message:"ok", data: {ok: true, mode: "keepLast", keepRevisions: 50}}`
634+
* `{code: 1, message:"padID does not exist", data: null}`
635+
* `{code: 1, message:"keepRevisions must be a non-negative integer", data: null}`
636+
622637
#### getReadOnlyID(padID)
623638
* API >= 1
624639

src/node/handler/APIHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ version['1.3.0'] = {
144144

145145
version['1.3.1'] = {
146146
...version['1.3.0'],
147-
compactPad: ['padID', 'authorId'],
147+
compactPad: ['padID', 'keepRevisions'],
148148
};
149149

150150

src/tests/backend/specs/compactPad.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
import {generateJWTToken} from "../common";
4+
35
const assert = require('assert').strict;
46
const common = require('../common');
57
const padManager = require('../../../node/db/PadManager');
@@ -10,6 +12,9 @@ const api = require('../../../node/db/API');
1012
// verify the public-API wiring and argument handling.
1113
describe(__filename, function () {
1214
let padId: string;
15+
let agent: any;
16+
17+
before(async function () { agent = await common.init(); });
1318

1419
beforeEach(async function () {
1520
padId = common.randomString();
@@ -80,4 +85,38 @@ describe(__filename, function () {
8085
/keepRevisions must be a non-negative integer/);
8186
});
8287
});
88+
89+
// Verifies the APIHandler dispatch wiring — i.e. that `keepRevisions`
90+
// travels from the URL query string to the API function under the
91+
// right argument name. This catches regressions where the handler's
92+
// version map gets renamed without updating the function signature.
93+
describe('HTTP API dispatch (1.3.1)', function () {
94+
it('passes keepRevisions from query string into compactPad', async function () {
95+
const pad = await padManager.getPad(padId);
96+
for (let i = 0; i < 5; i++) await pad.appendText(`http-line-${i}\n`);
97+
98+
const res = await agent.get(
99+
`/api/1.3.1/compactPad?padID=${padId}&keepRevisions=2`)
100+
.set('authorization', await generateJWTToken())
101+
.expect(200)
102+
.expect('Content-Type', /json/);
103+
104+
assert.strictEqual(res.body.code, 0, JSON.stringify(res.body));
105+
assert.strictEqual(res.body.data.mode, 'keepLast');
106+
assert.strictEqual(res.body.data.keepRevisions, 2);
107+
});
108+
109+
it('collapses all history when keepRevisions is absent from URL', async function () {
110+
const pad = await padManager.getPad(padId);
111+
for (let i = 0; i < 3; i++) await pad.appendText(`http-all-${i}\n`);
112+
113+
const res = await agent.get(`/api/1.3.1/compactPad?padID=${padId}`)
114+
.set('authorization', await generateJWTToken())
115+
.expect(200)
116+
.expect('Content-Type', /json/);
117+
118+
assert.strictEqual(res.body.code, 0, JSON.stringify(res.body));
119+
assert.deepStrictEqual(res.body.data, {ok: true, mode: 'all'});
120+
});
121+
});
83122
});

0 commit comments

Comments
 (0)