From abfa9b73a71902e212056cf89763cb2624b685f8 Mon Sep 17 00:00:00 2001 From: brobert Date: Mon, 29 Sep 2025 23:27:22 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20a=C3=B1adir=20alias=20para=20comandos?= =?UTF-8?q?=20de=20admin=20y=20actualizar=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: aider (openrouter/openai/gpt-5) --- src/services/admin.ts | 24 ++--- tests/unit/server/admin-approval.test.ts | 107 +++++++++++++++++++++++ 2 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/services/admin.ts b/src/services/admin.ts index 641cc67..cffd537 100644 --- a/src/services/admin.ts +++ b/src/services/admin.ts @@ -38,11 +38,11 @@ export class AdminService { private static help(): string { return [ 'Comandos de administración:', - '- /admin pendientes', - '- /admin habilitar-aquí', - '- /admin deshabilitar-aquí', - '- /admin allow-group ', - '- /admin block-group ', + '- /admin pendientes (alias: pending, pend)', + '- /admin habilitar-aquí (alias: enable)', + '- /admin deshabilitar-aquí (alias: disable)', + '- /admin allow-group (alias: allow)', + '- /admin block-group (alias: block)', ].join('\n'); } @@ -66,7 +66,7 @@ export class AdminService { const rest = lower.slice('/admin'.length).trim(); // /admin pendientes - if (rest === 'pendientes') { + if (rest === 'pendientes' || rest === 'pending' || rest === 'pend') { const rows = AllowedGroups.listByStatus('pending'); if (!rows || rows.length === 0) { return [{ recipient: sender, message: '✅ No hay grupos pendientes.' }]; @@ -79,7 +79,7 @@ export class AdminService { } // /admin habilitar-aquí - if (rest === 'habilitar-aquí' || rest === 'habilitar-aqui') { + if (rest === 'habilitar-aquí' || rest === 'habilitar-aqui' || rest === 'enable') { if (!isGroupId(ctx.groupId)) { return [{ recipient: sender, message: 'ℹ️ Este comando se debe usar dentro de un grupo.' }]; } @@ -89,7 +89,7 @@ export class AdminService { } // /admin deshabilitar-aquí - if (rest === 'deshabilitar-aquí' || rest === 'deshabilitar-aqui') { + if (rest === 'deshabilitar-aquí' || rest === 'deshabilitar-aqui' || rest === 'disable') { if (!isGroupId(ctx.groupId)) { return [{ recipient: sender, message: 'ℹ️ Este comando se debe usar dentro de un grupo.' }]; } @@ -99,8 +99,8 @@ export class AdminService { } // /admin allow-group - if (rest.startsWith('allow-group ')) { - const arg = rest.slice('allow-group '.length).trim(); + if (rest.startsWith('allow-group ') || rest.startsWith('allow ')) { + const arg = (rest.startsWith('allow-group ') ? rest.slice('allow-group '.length) : rest.slice('allow '.length)).trim(); if (!isGroupId(arg)) { return [{ recipient: sender, message: '⚠️ Debes indicar un group_id válido terminado en @g.us' }]; } @@ -110,8 +110,8 @@ export class AdminService { } // /admin block-group - if (rest.startsWith('block-group ')) { - const arg = rest.slice('block-group '.length).trim(); + if (rest.startsWith('block-group ') || rest.startsWith('block ')) { + const arg = (rest.startsWith('block-group ') ? rest.slice('block-group '.length) : rest.slice('block '.length)).trim(); if (!isGroupId(arg)) { return [{ recipient: sender, message: '⚠️ Debes indicar un group_id válido terminado en @g.us' }]; } diff --git a/tests/unit/server/admin-approval.test.ts b/tests/unit/server/admin-approval.test.ts index 698cdc6..657ccff 100644 --- a/tests/unit/server/admin-approval.test.ts +++ b/tests/unit/server/admin-approval.test.ts @@ -108,4 +108,111 @@ describe('WebhookServer - /admin aprobación en modo enforce', () => { const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'another-group@g.us'`).get() as any; expect(row == null).toBe(true); }); + + test('admin puede habilitar el grupo actual con alias /admin enable', async () => { + const payload = { + event: 'messages.upsert', + instance: 'test-instance', + data: { + key: { + remoteJid: 'new-group-alias@g.us', + participant: '1234567890@s.whatsapp.net' + }, + message: { conversation: '/admin enable' } + } + }; + + const res = await WebhookServer.handleRequest(createTestRequest(payload)); + expect(res.status).toBe(200); + + // Debe haber respuesta de confirmación encolada + expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0); + + // El grupo debe figurar como allowed + const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'new-group-alias@g.us'`).get() as any; + expect(row && String(row.status)).toBe('allowed'); + }); + + test('admin puede deshabilitar el grupo actual con alias /admin disable', async () => { + const payload = { + event: 'messages.upsert', + instance: 'test-instance', + data: { + key: { + remoteJid: 'disable-group@g.us', + participant: '1234567890@s.whatsapp.net' + }, + message: { conversation: '/admin disable' } + } + }; + + const res = await WebhookServer.handleRequest(createTestRequest(payload)); + expect(res.status).toBe(200); + + expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0); + + const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'disable-group@g.us'`).get() as any; + expect(row && String(row.status)).toBe('blocked'); + }); + + test('admin puede permitir un grupo por JID con alias /admin allow ', async () => { + const payload = { + event: 'messages.upsert', + instance: 'test-instance', + data: { + key: { + remoteJid: 'some-group@g.us', + participant: '1234567890@s.whatsapp.net' + }, + message: { conversation: '/admin allow target-allow@g.us' } + } + }; + + const res = await WebhookServer.handleRequest(createTestRequest(payload)); + expect(res.status).toBe(200); + + const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'target-allow@g.us'`).get() as any; + expect(row && String(row.status)).toBe('allowed'); + }); + + test('admin puede bloquear un grupo por JID con alias /admin block ', async () => { + const payload = { + event: 'messages.upsert', + instance: 'test-instance', + data: { + key: { + remoteJid: 'some-group@g.us', + participant: '1234567890@s.whatsapp.net' + }, + message: { conversation: '/admin block target-block@g.us' } + } + }; + + const res = await WebhookServer.handleRequest(createTestRequest(payload)); + expect(res.status).toBe(200); + + const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'target-block@g.us'`).get() as any; + expect(row && String(row.status)).toBe('blocked'); + }); + + test('admin puede ver pendientes con alias /admin pending', async () => { + const payload = { + event: 'messages.upsert', + instance: 'test-instance', + data: { + key: { + remoteJid: 'some-group@g.us', + participant: '1234567890@s.whatsapp.net' + }, + message: { conversation: '/admin pending' } + } + }; + + const res = await WebhookServer.handleRequest(createTestRequest(payload)); + expect(res.status).toBe(200); + + const out = SimulatedResponseQueue.get(); + expect(out.length).toBe(1); + expect(String(out[0].message).toLowerCase()).toContain('no hay grupos pendientes'); + }); });