diff --git a/src/app/api/conversations/archive/route.js b/src/app/api/conversations/archive/route.js index 0db31868..5e557ad6 100644 --- a/src/app/api/conversations/archive/route.js +++ b/src/app/api/conversations/archive/route.js @@ -6,9 +6,14 @@ import { NextResponse } from 'next/server'; import { withAuth } from '@/lib/api/middleware/auth.js'; +function normalizeConversationId(conversationId) { + return typeof conversationId === 'string' ? conversationId.trim() : ''; +} + export const POST = withAuth(async ({ request, locals }) => { try { - const { conversationId } = await request.json(); + const { conversationId: rawConversationId } = await request.json(); + const conversationId = normalizeConversationId(rawConversationId); if (!conversationId) { return NextResponse.json({ error: 'Missing conversationId' }, { status: 400 }); @@ -39,4 +44,4 @@ export const POST = withAuth(async ({ request, locals }) => { console.error('Archive conversation error:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } -}); \ No newline at end of file +}); diff --git a/src/app/api/conversations/archive/route.test.js b/src/app/api/conversations/archive/route.test.js new file mode 100644 index 00000000..0e1ce4c8 --- /dev/null +++ b/src/app/api/conversations/archive/route.test.js @@ -0,0 +1,64 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mocks = vi.hoisted(() => ({ + rpc: vi.fn() +})); + +vi.mock('@/lib/api/middleware/auth.js', () => ({ + withAuth: (handler) => (request, context) => + handler({ + request, + locals: { + supabase: { + rpc: mocks.rpc + }, + user: { id: 'auth-user-id' } + }, + context + }) +})); + +function createRequest(conversationId) { + return { + json: vi.fn().mockResolvedValue({ conversationId }) + }; +} + +describe('conversation archive routes', () => { + beforeEach(() => { + vi.resetModules(); + vi.clearAllMocks(); + mocks.rpc.mockResolvedValue({ data: true, error: null }); + }); + + it('trims conversation ids before archiving', async () => { + const { POST } = await import('./route.js'); + const response = await POST(createRequest(' conversation-1 ')); + + expect(response.status).toBe(200); + expect(mocks.rpc).toHaveBeenCalledWith('archive_conversation', { + conversation_uuid: 'conversation-1', + user_uuid: 'auth-user-id' + }); + }); + + it('rejects blank archive conversation ids before calling the database', async () => { + const { POST } = await import('./route.js'); + const response = await POST(createRequest(' ')); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body).toEqual({ error: 'Missing conversationId' }); + expect(mocks.rpc).not.toHaveBeenCalled(); + }); + + it('rejects blank unarchive conversation ids before calling the database', async () => { + const { POST } = await import('../unarchive/route.js'); + const response = await POST(createRequest(' ')); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body).toEqual({ error: 'Missing conversationId' }); + expect(mocks.rpc).not.toHaveBeenCalled(); + }); +}); diff --git a/src/app/api/conversations/unarchive/route.js b/src/app/api/conversations/unarchive/route.js index f865bcba..15dc3df2 100644 --- a/src/app/api/conversations/unarchive/route.js +++ b/src/app/api/conversations/unarchive/route.js @@ -6,9 +6,14 @@ import { NextResponse } from 'next/server'; import { withAuth } from '@/lib/api/middleware/auth.js'; +function normalizeConversationId(conversationId) { + return typeof conversationId === 'string' ? conversationId.trim() : ''; +} + export const POST = withAuth(async ({ request, locals }) => { try { - const { conversationId } = await request.json(); + const { conversationId: rawConversationId } = await request.json(); + const conversationId = normalizeConversationId(rawConversationId); if (!conversationId) { return NextResponse.json({ error: 'Missing conversationId' }, { status: 400 }); @@ -39,4 +44,4 @@ export const POST = withAuth(async ({ request, locals }) => { console.error('Unarchive conversation error:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } -}); \ No newline at end of file +});