Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import { NextResponse, type NextRequest } from 'next/server' import { withAuth } from '@/lib/auth/withAuth' import { getUserId } from '@/lib/viewer' import { db } from '@/db' import * as schema from '@/db/schema' import { eq, desc, and, inArray, isNull } from 'drizzle-orm' import type { CreationData } from '@/db/schema/euclid-creations' /** POST /api/euclid/creations — save a new playground creation */ export const POST = withAuth(async (request: NextRequest) => { try { const userId = await getUserId() const body = await request.json() const { data, thumbnail, isPublic, playerId, title } = body as { data: CreationData thumbnail?: string isPublic?: boolean playerId?: string | null title?: string | null } if (!data || !data.actions) { return NextResponse.json({ error: 'Missing creation data' }, { status: 400 }) } const [creation] = await db .insert(schema.euclidCreations) .values({ userId, playerId: playerId ?? null, data, thumbnail: thumbnail ?? null, isPublic: isPublic ?? false, title: title ?? null, }) .returning() return NextResponse.json({ id: creation.id }, { status: 201 }) } catch (err) { console.error('[euclid/creations] POST failed:', err) return NextResponse.json({ error: 'Failed to save creation' }, { status: 500 }) } }) /** * GET /api/euclid/creations * * Query params: * ?mine=true — scoped to current user/player (requires auth) * ?playerId=<id> — filter to a specific player (combine with mine=true) * if mine=true and no playerId, returns user-level creations (null player) * ?isPublic=true — filter to public only (combine with mine=true for "my published") * ?ids=id1,id2,... — fetch specific IDs (for "seen" tab) * ?limit=N — max results (default 50, max 100) */ export const GET = withAuth(async (request: NextRequest) => { try { const url = new URL(request.url) const mine = url.searchParams.get('mine') === 'true' const playerIdParam = url.searchParams.get('playerId') const isPublicFilter = url.searchParams.get('isPublic') const idsParam = url.searchParams.get('ids') const limit = Math.min(Number(url.searchParams.get('limit') ?? '50'), 100) const cols = { id: schema.euclidCreations.id, thumbnail: schema.euclidCreations.thumbnail, isPublic: schema.euclidCreations.isPublic, createdAt: schema.euclidCreations.createdAt, title: schema.euclidCreations.title, updatedAt: schema.euclidCreations.updatedAt, } // Fetch specific IDs (for "seen" tab) if (idsParam) { const ids = idsParam.split(',').filter(Boolean).slice(0, 100) if (ids.length === 0) return NextResponse.json({ creations: [] }) const creations = await db .select(cols) .from(schema.euclidCreations) .where(inArray(schema.euclidCreations.id, ids)) .all() return NextResponse.json({ creations }) } const conditions = [] if (mine) { if (playerIdParam) { // Player-scoped: show this player's creations conditions.push(eq(schema.euclidCreations.playerId, playerIdParam)) } else { // User-scoped (no player selected): show user's creations with no player const userId = await getUserId() conditions.push(eq(schema.euclidCreations.userId, userId)) conditions.push(isNull(schema.euclidCreations.playerId)) } } if (isPublicFilter !== null) { conditions.push(eq(schema.euclidCreations.isPublic, isPublicFilter === 'true')) } else if (!mine) { // Default public gallery: only public conditions.push(eq(schema.euclidCreations.isPublic, true)) } const creations = await db .select(cols) .from(schema.euclidCreations) .where(conditions.length > 0 ? and(...conditions) : undefined) .orderBy(desc(schema.euclidCreations.createdAt)) .limit(limit) .all() return NextResponse.json({ creations }) } catch (err) { console.error('[euclid/creations] GET failed:', err) return NextResponse.json({ error: 'Failed to fetch creations' }, { status: 500 }) } }) |