blocked: blocked numbers page and API; M6 milestone check
/api/blocked-numbers stores numbers normalized (any input format) and mirrors them to AstDB SP/BLOCK/<number>, which every trunk entry checks (Hangup 21); the AstDB resync on connect includes them. Blocked numbers page: add with a note, unblock. e2e m6-check runs the M6 milestone scenario with real calls into a trunk entry: DID → office hours (closed → voicemail; *31N from an admin's phone forces open) → menu (1 → ring group ringing two phones together, 2 → a user), and a caller blocked in the UI is rejected while others get through. Task: M6-T8
This commit is contained in:
1 parent
57e0e3dac2
commit
4fc0fb4084
12 files changed
+559
-3
No files matched your search
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// M6-T8: /api/blocked-numbers and the AstDB mirror (04 §5.5).
|
||||
import type { LightMyRequestResponse } from 'fastify';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { syncAstDb } from '../src/services/astdb.ts';
|
||||
import { hasTestDb } from './db.ts';
|
||||
import { ADMIN, H, createTestApp } from './app.ts';
|
||||
|
||||
describe.skipIf(!hasTestDb)('/api/blocked-numbers', () => {
|
||||
let t: Awaited<ReturnType<typeof createTestApp>>;
|
||||
let req: (method: string, url: string, payload?: unknown) => Promise<LightMyRequestResponse>;
|
||||
|
||||
beforeAll(async () => {
|
||||
t = await createTestApp();
|
||||
await t.clearMustChange(ADMIN.email);
|
||||
const cookie = await t.login(ADMIN.email, ADMIN.password);
|
||||
req = (method, url, payload) =>
|
||||
t.app.inject({
|
||||
method: method as 'GET',
|
||||
url,
|
||||
payload: payload as object,
|
||||
headers: { ...H, cookie },
|
||||
});
|
||||
});
|
||||
afterAll(() => t?.close());
|
||||
|
||||
it('blocks a number in any format (stored normalized), mirrors AstDB, unblocks', async () => {
|
||||
const r = await req('POST', '/api/blocked-numbers', {
|
||||
number: '(312) 555-0199',
|
||||
reason: 'Spam',
|
||||
});
|
||||
expect(r.statusCode, r.body).toBe(201);
|
||||
expect(r.json()).toMatchObject({ number: '13125550199', reason: 'Spam' });
|
||||
expect(t.ami.actions.at(-1)).toEqual({
|
||||
Action: 'DBPut',
|
||||
Family: 'SP',
|
||||
Key: 'BLOCK/13125550199',
|
||||
Val: '1',
|
||||
});
|
||||
expect(
|
||||
(await req('POST', '/api/blocked-numbers', { number: '+1 312 555 0199' })).statusCode,
|
||||
).toBe(409);
|
||||
expect((await req('POST', '/api/blocked-numbers', { number: 'spam' })).statusCode).toBe(400);
|
||||
|
||||
t.ami.actions.length = 0;
|
||||
await syncAstDb(t.db, t.ami);
|
||||
expect(t.ami.actions).toContainEqual({
|
||||
Action: 'DBPut',
|
||||
Family: 'SP',
|
||||
Key: 'BLOCK/13125550199',
|
||||
Val: '1',
|
||||
});
|
||||
|
||||
expect((await req('DELETE', `/api/blocked-numbers/${r.json().id}`)).statusCode).toBe(200);
|
||||
expect(t.ami.actions.at(-1)).toEqual({
|
||||
Action: 'DBDel',
|
||||
Family: 'SP',
|
||||
Key: 'BLOCK/13125550199',
|
||||
});
|
||||
expect((await req('GET', '/api/blocked-numbers')).json().items).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user