Added extension functionality

This commit is contained in:
Emil
2026-02-21 11:39:45 +01:00
parent 2f83f232c6
commit 026497ed75
132 changed files with 3533 additions and 60 deletions
@@ -0,0 +1,51 @@
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(
_request: Request,
{ params }: { params: Promise<{ sector: string; slug: string }> }
) {
const { sector, slug } = await params
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { data } = await supabase
.from('extension_toggles')
.select('*')
.eq('user_id', user.id)
.eq('sector_slug', sector)
.eq('extension_slug', slug)
.single()
return NextResponse.json({ data: data ?? { enabled: false } })
}
export async function DELETE(
_request: Request,
{ params }: { params: Promise<{ sector: string; slug: string }> }
) {
const { sector, slug } = await params
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { error } = await supabase
.from('extension_toggles')
.delete()
.eq('user_id', user.id)
.eq('sector_slug', sector)
.eq('extension_slug', slug)
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 })
}
return NextResponse.json({ success: true })
}
@@ -0,0 +1,105 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import {
createMockRequest,
parseJsonResponse,
createQueuedMockSupabase,
makeExtensionToggle,
} from '@/tests/helpers'
const { supabase: mockSupabase, enqueue, reset } = createQueuedMockSupabase()
vi.mock('@/lib/supabase/server', () => ({
createClient: () => Promise.resolve(mockSupabase),
}))
import { GET, POST } from '../route'
describe('GET /api/extensions/toggles', () => {
const mockUser = { id: 'user-1', email: 'test@test.se' }
beforeEach(() => {
vi.clearAllMocks()
reset()
mockSupabase.auth.getUser.mockResolvedValue({ data: { user: mockUser } })
})
it('returns 401 when not authenticated', async () => {
mockSupabase.auth.getUser.mockResolvedValue({ data: { user: null } })
const response = await GET()
const { status, body } = await parseJsonResponse(response)
expect(status).toBe(401)
expect(body).toEqual({ error: 'Unauthorized' })
})
it('returns enabled toggles for user', async () => {
const toggles = [
makeExtensionToggle({ extension_slug: 'receipt-ocr' }),
makeExtensionToggle({ extension_slug: 'ai-chat' }),
]
enqueue({ data: toggles, error: null })
const response = await GET()
const { status, body } = await parseJsonResponse<{ data: unknown[] }>(response)
expect(status).toBe(200)
expect(body.data).toEqual(toggles)
expect(mockSupabase.from).toHaveBeenCalledWith('extension_toggles')
})
})
describe('POST /api/extensions/toggles', () => {
const mockUser = { id: 'user-1', email: 'test@test.se' }
beforeEach(() => {
vi.clearAllMocks()
reset()
mockSupabase.auth.getUser.mockResolvedValue({ data: { user: mockUser } })
})
it('returns 401 when not authenticated', async () => {
mockSupabase.auth.getUser.mockResolvedValue({ data: { user: null } })
const request = createMockRequest('/api/extensions/toggles', {
method: 'POST',
body: { sector_slug: 'general', extension_slug: 'receipt-ocr', enabled: true },
})
const response = await POST(request)
const { status, body } = await parseJsonResponse(response)
expect(status).toBe(401)
expect(body).toEqual({ error: 'Unauthorized' })
})
it('returns 400 when missing fields', async () => {
const request = createMockRequest('/api/extensions/toggles', {
method: 'POST',
body: { sector_slug: 'general' },
})
const response = await POST(request)
const { status, body } = await parseJsonResponse<{ error: string }>(response)
expect(status).toBe(400)
expect(body.error).toBe('sector_slug, extension_slug, and enabled are required')
})
it('upserts toggle and returns data', async () => {
const toggle = makeExtensionToggle({
sector_slug: 'general',
extension_slug: 'receipt-ocr',
enabled: true,
})
enqueue({ data: toggle, error: null })
const request = createMockRequest('/api/extensions/toggles', {
method: 'POST',
body: { sector_slug: 'general', extension_slug: 'receipt-ocr', enabled: true },
})
const response = await POST(request)
const { status, body } = await parseJsonResponse<{ data: unknown }>(response)
expect(status).toBe(200)
expect(body.data).toEqual(toggle)
expect(mockSupabase.from).toHaveBeenCalledWith('extension_toggles')
})
})
+62
View File
@@ -0,0 +1,62 @@
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { data, error } = await supabase
.from('extension_toggles')
.select('*')
.eq('user_id', user.id)
.eq('enabled', true)
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 })
}
return NextResponse.json({ data })
}
export async function POST(request: Request) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { sector_slug, extension_slug, enabled } = body
if (!sector_slug || !extension_slug || typeof enabled !== 'boolean') {
return NextResponse.json(
{ error: 'sector_slug, extension_slug, and enabled are required' },
{ status: 400 }
)
}
const { data, error } = await supabase
.from('extension_toggles')
.upsert(
{
user_id: user.id,
sector_slug,
extension_slug,
enabled,
},
{ onConflict: 'user_id,sector_slug,extension_slug' }
)
.select()
.single()
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 })
}
return NextResponse.json({ data })
}