| import { NextRequest, NextResponse } from 'next/server' |
| import { hashPin, generateSessionHash, generateCode, createCodePair } from 'lib/codes' |
| import { createRoom } from 'lib/roomService' |
| import { setAnonymousSession } from 'lib/session' |
| import { getCodeByCode, getCodeById, insertCode, updateCode, updateRoom, updateCodesRoomId } from 'lib/persistence' |
| import { logEvent } from 'lib/logger' |
|
|
| export async function POST(request: NextRequest) { |
| try { |
| const body = await request.json() |
| const { code, pin, userAgent, codes } = body |
|
|
| console.log('[codes/setup] Incoming request body:', { code, hasPin: Boolean(pin), userAgent }) |
|
|
| if (!code) { |
| console.warn('[codes/setup] Missing code in request body') |
| return NextResponse.json( |
| { error: 'Chyb¡ k¢d m¡stnosti' }, |
| { status: 400 } |
| ) |
| } |
|
|
| let codeData = await getCodeByCode(code) |
|
|
| |
| if (!codeData || codeData?.used === 1) { |
| console.warn('[codes/setup] Code missing or already used - creating new pair for user', { requested: code.toUpperCase(), existing: !!codeData, used: codeData?.used ?? null }) |
| try { |
| const { code1, code2 } = await createCodePair() |
| const createdPrimary = await insertCode({ |
| code: code1, |
| linked_to: null, |
| used: null, |
| used_count: 0 |
| }) |
|
|
| if (!createdPrimary) { |
| throw new Error('Failed to create primary code') |
| } |
|
|
| const createdSecondary = await insertCode({ |
| code: code2, |
| linked_to: createdPrimary.id, |
| used: null, |
| used_count: 0 |
| }) |
|
|
| if (!createdSecondary) { |
| |
| await updateCode(createdPrimary.id, {} as any) |
| throw new Error('Failed to create secondary code') |
| } |
|
|
| const linkResult = await updateCode(createdPrimary.id, { linked_to: createdSecondary.id }) |
| if (!linkResult) { |
| throw new Error('Failed to link primary and secondary codes') |
| } |
|
|
| codeData = { ...createdPrimary, linked_to: createdSecondary.id } |
| } catch (createErr) { |
| console.error('[codes/setup] Failed to create code pair fallback:', createErr) |
| return NextResponse.json( |
| { error: 'Nepodaýilo se vytvoýit k¢d' }, |
| { status: 500 } |
| ) |
| } |
| } |
|
|
| |
| if (Array.isArray(codes) && codes.length > 0) { |
| const normalized = Array.from(new Set(codes.map((c: any) => String(c).toUpperCase().trim()).filter(Boolean))) |
| if (normalized.length < 2) { |
| console.warn('[codes/setup] multi-code flow requires at least 2 codes') |
| } else { |
| |
| const rows: Array<any> = [] |
| for (const candidate of normalized) { |
| let cd = await getCodeByCode(candidate) |
| if (!cd) { |
| cd = await insertCode({ code: candidate, linked_to: null, used: null, used_count: 0 }) |
| if (!cd) { |
| console.error('[codes/setup] failed to create code', candidate) |
| return NextResponse.json({ error: 'Nepodařilo se vytvořit kódy' }, { status: 500 }) |
| } |
| } |
| rows.push(cd) |
| } |
|
|
| |
| const roomId = await createRoom(rows[0].id, rows[1].id) |
| const remaining = rows.slice(2).map((r) => r.id) |
| if (remaining.length > 0) { |
| await updateCodesRoomId(remaining, roomId) |
| } |
|
|
| await logEvent({ module: 'codes', operation: 'setup_multi', data: { codes: normalized, roomId } }) |
|
|
| return NextResponse.json({ success: true, roomId, codes: normalized }) |
| } |
| } |
|
|
| |
| if (!codeData || !codeData.linked_to) { |
| console.warn('[codes/setup] code.linked_to missing, creating secondary code', { codeId: codeData?.id || null }) |
| let createdSecondary = null |
| for (let i = 0; i < 5; i++) { |
| const candidate = generateCode() |
| const sec = await insertCode({ |
| code: candidate, |
| linked_to: codeData!.id, |
| used: null, |
| used_count: 0 |
| }) |
|
|
| if (sec) { |
| createdSecondary = sec |
| break |
| } |
| } |
|
|
| if (!createdSecondary) { |
| console.error('[codes/setup] Failed to create a linked secondary code') |
| return NextResponse.json({ error: 'Nepodaýilo se vytvoýit p rovì k¢d' }, { status: 500 }) |
| } |
|
|
| const linkResult = await updateCode(codeData!.id, { linked_to: createdSecondary.id }) |
|
|
| if (!linkResult) { |
| console.error('[codes/setup] Failed to link primary to secondary') |
| return NextResponse.json({ error: 'Nepodaýilo se aktualizovat p rov‚ k¢dy' }, { status: 500 }) |
| } |
|
|
| codeData!.linked_to = createdSecondary.id |
| } |
|
|
| const linkedCode = await getCodeById(codeData!.linked_to!) |
|
|
| if (!linkedCode) { |
| return NextResponse.json( |
| { error: 'P rovì k¢d nenalezen' }, |
| { status: 400 } |
| ) |
| } |
|
|
| const roomId = await createRoom(codeData!.id, linkedCode.id) |
|
|
| const sessionHash = generateSessionHash(code, userAgent || '') |
| let pinHash: string | undefined |
|
|
| if (pin) { |
| pinHash = await hashPin(pin) |
| } |
|
|
| const now = new Date().toISOString() |
|
|
| |
| const updatePayload: Record<string, unknown> = { |
| used: 1, |
| room_id: roomId, |
| pin_hash: pinHash || null, |
| session_hash: !pin ? sessionHash : null, |
| date_first: now, |
| date_last: now, |
| used_count: 1 |
| } |
| |
|
|
| const updated = await updateCode(codeData!.id, updatePayload as any) |
| const updateErr = !updated ? { message: 'Update failed' } : null |
|
|
| if (updateErr) { |
| |
| try { |
| await updateRoom(roomId, { status: 0 }) |
| } catch (cleanupErr) { |
| console.error('Cleanup failed after codes update error:', cleanupErr) |
| } |
| console.error('Failed to update code after creating room:', updateErr) |
| return NextResponse.json( |
| { error: 'Nepodaýilo se oznaŸit k¢d jako pou§itì (RLS nebo db chyba)', detail: updateErr.message || updateErr }, |
| { status: 500 } |
| ) |
| } |
|
|
| |
| if (!pin) { |
| await setAnonymousSession({ |
| codeId: codeData!.id, |
| sessionHash, |
| roomId, |
| expiresAt: Date.now() + (10 * 365 * 24 * 60 * 60 * 1000) |
| }) |
| } else { |
| |
| await setAnonymousSession({ |
| codeId: codeData!.id, |
| sessionHash: Buffer.from(`${codeData!.id}:${Date.now()}`).toString('base64'), |
| roomId, |
| expiresAt: Date.now() + (30 * 24 * 60 * 60 * 1000) |
| }) |
| } |
|
|
| await logEvent({ |
| module: 'codes', |
| operation: 'setup', |
| data: { codeId: codeData!.id, roomId, pinSet: Boolean(pin) }, |
| ip: (request as any).headers?.get?.('x-forwarded-for') || null, |
| userAgent: (request as any).headers?.get?.('user-agent') || null |
| }) |
|
|
| return NextResponse.json({ |
| success: true, |
| roomId, |
| codeId: codeData!.id |
| }) |
| } catch (error) { |
| console.error('Code setup error:', error) |
| return NextResponse.json( |
| { error: 'Vnitýn¡ chyba serveru' }, |
| { status: 500 } |
| ) |
| } |
| } |
|
|