import { NextRequest, NextResponse } from 'next/server'; import { prisma, projectService } from '@/lib/prisma'; import { requireSessionAuth } from '@/lib/auth'; export async function POST(request: NextRequest) { try { const isAdminRequest = request.headers.get('x-admin-request') === 'true'; if (!isAdminRequest) return NextResponse.json({ error: 'Admin access required' }, { status: 403 }); const authError = requireSessionAuth(request); if (authError) return authError; const body = await request.json(); // Validate import data structure if (!body.projects || !Array.isArray(body.projects)) { return NextResponse.json( { error: 'Invalid import data format' }, { status: 400 } ); } const results = { imported: 0, skipped: 0, errors: [] as string[] }; // Import SiteSettings (optional) if (body.siteSettings && typeof body.siteSettings === 'object') { try { await prisma.siteSettings.upsert({ where: { id: 1 }, create: { id: 1, ...(body.siteSettings as Record) } as any, update: { ...(body.siteSettings as Record) } as any, }); } catch { // non-blocking } } // Import CMS content pages (optional) if (Array.isArray(body.contentPages)) { for (const page of body.contentPages) { try { if (!page?.key) continue; const upserted = await prisma.contentPage.upsert({ where: { key: page.key }, create: { key: page.key, status: page.status || 'PUBLISHED' }, update: { status: page.status || 'PUBLISHED' }, }); if (Array.isArray(page.translations)) { for (const tr of page.translations) { if (!tr?.locale || !tr?.content) continue; await prisma.contentPageTranslation.upsert({ where: { pageId_locale: { pageId: upserted.id, locale: tr.locale } }, create: { pageId: upserted.id, locale: tr.locale, title: tr.title || null, slug: tr.slug || null, content: tr.content, metaDescription: tr.metaDescription || null, keywords: tr.keywords || null, } as any, update: { title: tr.title || null, slug: tr.slug || null, content: tr.content, metaDescription: tr.metaDescription || null, keywords: tr.keywords || null, } as any, }); } } } catch (error) { results.errors.push(`Failed to import content page "${page?.key}": ${error instanceof Error ? error.message : 'Unknown error'}`); } } } // Preload existing titles once (avoid O(n^2) DB reads during import) const existingProjectsResult = await projectService.getAllProjects({ limit: 10000 }); const existingProjects = existingProjectsResult.projects || existingProjectsResult; const existingTitles = new Set(existingProjects.map(p => p.title)); const existingSlugs = new Set(existingProjects.map(p => (p as unknown as { slug?: string }).slug).filter(Boolean)); // Process each project for (const projectData of body.projects) { try { // Check if project already exists (by title) const exists = existingTitles.has(projectData.title); if (exists) { results.skipped++; results.errors.push(`Project "${projectData.title}" already exists`); continue; } // Create new project const created = await projectService.createProject({ slug: projectData.slug, defaultLocale: projectData.defaultLocale || 'en', title: projectData.title, description: projectData.description, content: projectData.content, tags: projectData.tags || [], category: projectData.category, featured: projectData.featured || false, github: projectData.github, live: projectData.live, published: projectData.published !== false, // Default to true imageUrl: projectData.imageUrl, difficulty: projectData.difficulty || 'Intermediate', timeToComplete: projectData.timeToComplete, technologies: projectData.technologies || [], challenges: projectData.challenges || [], lessonsLearned: projectData.lessonsLearned || [], futureImprovements: projectData.futureImprovements || [], demoVideo: projectData.demoVideo, screenshots: projectData.screenshots || [], colorScheme: projectData.colorScheme || 'Dark', accessibility: projectData.accessibility !== false, // Default to true performance: projectData.performance || { lighthouse: 0, bundleSize: '0KB', loadTime: '0s' }, analytics: projectData.analytics || { views: 0, likes: 0, shares: 0 } }); // Import translations (optional, from export v2) if (Array.isArray(body.projectTranslations)) { for (const tr of body.projectTranslations) { if (!tr?.projectId || !tr?.locale) continue; // Map translation to created project by original slug/title when possible. // We match by slug if available in exported project list; otherwise by title. const exportedProject = body.projects.find((p: any) => p.id === tr.projectId); const exportedSlug = exportedProject?.slug; const matches = (exportedSlug && (created as any).slug === exportedSlug) || (!!exportedProject?.title && (created as any).title === exportedProject.title); if (!matches) continue; if (!tr.title || !tr.description) continue; await prisma.projectTranslation.upsert({ where: { projectId_locale: { projectId: (created as any).id, locale: tr.locale } }, create: { projectId: (created as any).id, locale: tr.locale, title: tr.title, description: tr.description, content: tr.content || null, metaDescription: tr.metaDescription || null, keywords: tr.keywords || null, ogImage: tr.ogImage || null, schema: tr.schema || null, } as any, update: { title: tr.title, description: tr.description, content: tr.content || null, metaDescription: tr.metaDescription || null, keywords: tr.keywords || null, ogImage: tr.ogImage || null, schema: tr.schema || null, } as any, }); } } results.imported++; existingTitles.add(projectData.title); if (projectData.slug) existingSlugs.add(projectData.slug); } catch (error) { results.skipped++; results.errors.push(`Failed to import "${projectData.title}": ${error instanceof Error ? error.message : 'Unknown error'}`); } } return NextResponse.json({ success: true, message: `Import completed: ${results.imported} imported, ${results.skipped} skipped`, results }); } catch (error) { console.error('Import error:', error); return NextResponse.json( { error: 'Failed to import projects' }, { status: 500 } ); } }