Skip to content

Commit f516b45

Browse files
CopilotJohnMcLear
andauthored
feat: support append via PATCH /post
Agent-Logs-Url: https://github.com/ether/ep_post_data/sessions/8d85ca65-9276-4233-a94b-83d25502c051 Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com>
1 parent a81d7a1 commit f516b45

3 files changed

Lines changed: 60 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ pnpm run plugins i ep_post_data
1111
## Usage
1212

1313
POST to `/post` to create or update a pad. Set the `X-PAD-ID` header to choose the pad name, otherwise a random ID is generated.
14+
Use `PATCH /post` to append content to an existing pad (or create it if it does not exist).
1415

1516
```bash
1617
# Create a pad with a random ID
1718
curl -X POST -d @datafile.txt http://localhost:9001/post
1819

1920
# Create or update a specific pad
2021
curl -X POST -d @datafile.txt -H 'X-PAD-ID: mypad' http://localhost:9001/post
22+
23+
# Append to a specific pad (or create it if missing)
24+
curl -X PATCH -d @datafile.txt -H 'X-PAD-ID: mypad' http://localhost:9001/post
2125
```
2226

2327
## Limits

index.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomStrin
66
const MAX_BODY_SIZE = 1024 * 1024; // 1 MB
77

88
exports.registerRoute = (hookName, args, callback) => {
9-
args.app.post('/post', (req, res) => {
9+
const upsertPadFromRequest = (req, res, shouldAppend) => {
1010
let padId = req.headers['x-pad-id'];
1111
if (padId === undefined) {
1212
padId = randomString(8);
@@ -49,15 +49,24 @@ exports.registerRoute = (hookName, args, callback) => {
4949
// Pad already exists so updating an existing pad.
5050
if (padExists) {
5151
try {
52-
console.debug('ep_post_data: Setting text!', padId, content);
53-
await API.setText(padId, content);
54-
res.send('Success updating pad');
52+
if (shouldAppend) {
53+
console.debug('ep_post_data: Appending text!', padId, content);
54+
await API.appendText(padId, content);
55+
res.send('Success appending to pad');
56+
} else {
57+
console.debug('ep_post_data: Setting text!', padId, content);
58+
await API.setText(padId, content);
59+
res.send('Success updating pad');
60+
}
5561
} catch (e) {
5662
console.error('ep_post_data: Error updating pad', padId, e);
5763
res.send('Error updating pad');
5864
}
5965
}
6066
});
61-
});
67+
};
68+
69+
args.app.post('/post', (req, res) => upsertPadFromRequest(req, res, false));
70+
args.app.patch('/post', (req, res) => upsertPadFromRequest(req, res, true));
6271
callback();
6372
};

static/tests/frontend-new/specs/smoke.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,51 @@ test.beforeEach(async ({page}) => {
55
await goToNewPad(page);
66
});
77

8+
const getPadIdFromUrl = (url: string) => {
9+
const match = /\/p\/([^/?#]+)/.exec(url);
10+
if (!match) throw new Error(`Failed to parse pad id from URL: ${url}`);
11+
return match[1];
12+
};
13+
814
test.describe('ep_post_data', () => {
915
test('pad loads with plugin installed', async ({page}) => {
1016
const padBody = await getPadBody(page);
1117
await expect(padBody).toBeVisible();
1218
});
19+
20+
test('PATCH /post appends text to an existing pad', async ({page}) => {
21+
const padId = getPadIdFromUrl(page.url());
22+
23+
const postResponse = await page.request.fetch('/post', {
24+
method: 'POST',
25+
headers: {'X-PAD-ID': padId},
26+
data: 'first',
27+
});
28+
expect(postResponse.ok()).toBeTruthy();
29+
30+
const patchResponse = await page.request.fetch('/post', {
31+
method: 'PATCH',
32+
headers: {'X-PAD-ID': padId},
33+
data: ' second',
34+
});
35+
expect(patchResponse.ok()).toBeTruthy();
36+
37+
const txtResponse = await page.request.get(`/p/${padId}/export/txt`);
38+
expect(txtResponse.ok()).toBeTruthy();
39+
expect((await txtResponse.text()).trimEnd()).toBe('first second');
40+
});
41+
42+
test('PATCH /post creates pad when it does not exist', async ({page}) => {
43+
const padId = `ep-post-data-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
44+
const patchResponse = await page.request.fetch('/post', {
45+
method: 'PATCH',
46+
headers: {'X-PAD-ID': padId},
47+
data: 'created via patch',
48+
});
49+
expect(patchResponse.ok()).toBeTruthy();
50+
51+
const txtResponse = await page.request.get(`/p/${padId}/export/txt`);
52+
expect(txtResponse.ok()).toBeTruthy();
53+
expect((await txtResponse.text()).trimEnd()).toBe('created via patch');
54+
});
1355
});

0 commit comments

Comments
 (0)