Catalog collect: per-IP budget and fill-only writes; bulk import moves to an admin/API-token route
This commit is contained in:
@@ -130,6 +130,25 @@ test('client cached search collection validates input and stores new metadata',
|
||||
expect(picks.results).toHaveLength(4);
|
||||
});
|
||||
|
||||
test('anonymous collection only fills blanks, is rate limited, and bulk import needs admin', async () => {
|
||||
const deny = async c => c.json({ ok: false }, 401);
|
||||
const allow = async (c, next) => c.req.header('x-test-admin') === 'yes' ? next() : deny(c);
|
||||
const app = new Hono(); registerCatalogRoutes(app, { adminAuth: allow });
|
||||
const card = { ...b, id: 'fillonlyvid', title: 'Original title' };
|
||||
const ip = { 'X-Forwarded-For': '203.0.113.9' };
|
||||
const post = (path, body, headers = {}) => app.request(path, { method: 'POST', headers: { 'Content-Type': 'application/json', ...headers }, body: JSON.stringify(body) });
|
||||
expect((await post('/api/catalog/collect', { cards: [card] }, ip)).status).toBe(200);
|
||||
await post('/api/catalog/collect', { cards: [{ ...card, title: 'Spam title' }] }, ip);
|
||||
const title = async () => JSON.parse((await db.execute({ sql: 'SELECT card FROM video_meta WHERE id=?', args: [card.id] })).rows[0].card).title;
|
||||
expect(await title()).toBe('Original title');
|
||||
for (let i = 0; i < 28; i++) await post('/api/catalog/collect', { cards: [] }, ip);
|
||||
expect((await post('/api/catalog/collect', { cards: [] }, ip)).status).toBe(429);
|
||||
expect((await post('/api/catalog/collect', { cards: [] }, { 'X-Forwarded-For': '203.0.113.10' })).status).toBe(200);
|
||||
expect((await post('/api/admin/catalog/import', { cards: [{ ...card, title: 'Fixed title' }] })).status).toBe(401);
|
||||
expect(await (await post('/api/admin/catalog/import', { cards: [{ ...card, title: 'Fixed title' }] }, { 'x-test-admin': 'yes' })).json()).toEqual({ ok: true, collected: 1 });
|
||||
expect(await title()).toBe('Fixed title');
|
||||
});
|
||||
|
||||
test('legacy backfill progresses with a durable cursor and finds unplayed search metadata', async () => {
|
||||
const card = { ...b, id: 'legacyvideo' };
|
||||
await cache.put('legacy', [card]);
|
||||
|
||||
Reference in New Issue
Block a user