/** * Projects API Routes * CRUD operations for projects */ import { db } from '../../db/client' import { projects } from '../../db/schema' import { eq } from 'drizzle-orm' import { randomUUID } from 'crypto' /** * Handle all project routes */ export async function handleProjectRoutes(req: Request, url: URL): Promise { const method = req.method const pathParts = url.pathname.split('/').filter(Boolean) // GET /api/projects - List all projects if (method === 'GET' && pathParts.length === 2) { return await listProjects() } // GET /api/projects/:id - Get single project if (method === 'GET' && pathParts.length === 3) { const projectId = pathParts[2] return await getProject(projectId) } // POST /api/projects - Create project if (method === 'POST' && pathParts.length === 2) { return await createProject(req) } // PATCH /api/projects/:id - Update project if (method === 'PATCH' && pathParts.length === 3) { const projectId = pathParts[2] return await updateProject(projectId, req) } // DELETE /api/projects/:id - Delete project if (method === 'DELETE' && pathParts.length === 3) { const projectId = pathParts[2] return await deleteProject(projectId) } return new Response('Not Found', { status: 404 }) } /** * List all projects */ async function listProjects(): Promise { try { const allProjects = await db.select().from(projects) return Response.json({ success: true, data: allProjects, count: allProjects.length, }) } catch (error) { console.error('Error listing projects:', error) return Response.json({ success: false, error: 'Failed to list projects', }, { status: 500 }) } } /** * Get single project */ async function getProject(projectId: string): Promise { try { const project = await db .select() .from(projects) .where(eq(projects.id, projectId)) .limit(1) if (project.length === 0) { return Response.json({ success: false, error: 'Project not found', }, { status: 404 }) } return Response.json({ success: true, data: project[0], }) } catch (error) { console.error('Error getting project:', error) return Response.json({ success: false, error: 'Failed to get project', }, { status: 500 }) } } /** * Create project */ async function createProject(req: Request): Promise { try { const body = await req.json() // Validate required fields if (!body.name) { return Response.json({ success: false, error: 'Name is required', }, { status: 400 }) } // Generate k8s namespace name from project name const k8sNamespace = `proj-${body.name.toLowerCase().replace(/[^a-z0-9-]/g, '-')}` const newProject = { id: randomUUID(), name: body.name, description: body.description || null, k8sNamespace, giteaRepoId: body.giteaRepoId || null, giteaRepoUrl: body.giteaRepoUrl || null, giteaOwner: body.giteaOwner || null, giteaRepoName: body.giteaRepoName || null, defaultBranch: body.defaultBranch || 'main', dockerImage: body.dockerImage || null, envVars: body.envVars || null, replicas: body.replicas || 1, cpuLimit: body.cpuLimit || '500m', memoryLimit: body.memoryLimit || '512Mi', status: body.status || 'active', } await db.insert(projects).values(newProject) return Response.json({ success: true, data: newProject, }, { status: 201 }) } catch (error) { console.error('Error creating project:', error) return Response.json({ success: false, error: 'Failed to create project', }, { status: 500 }) } } /** * Update project */ async function updateProject(projectId: string, req: Request): Promise { try { const body = await req.json() // Check if project exists const existing = await db .select() .from(projects) .where(eq(projects.id, projectId)) .limit(1) if (existing.length === 0) { return Response.json({ success: false, error: 'Project not found', }, { status: 404 }) } // Update only provided fields const updateData: any = {} if (body.name !== undefined) updateData.name = body.name if (body.description !== undefined) updateData.description = body.description if (body.giteaRepoId !== undefined) updateData.giteaRepoId = body.giteaRepoId if (body.giteaRepoUrl !== undefined) updateData.giteaRepoUrl = body.giteaRepoUrl if (body.giteaOwner !== undefined) updateData.giteaOwner = body.giteaOwner if (body.giteaRepoName !== undefined) updateData.giteaRepoName = body.giteaRepoName if (body.defaultBranch !== undefined) updateData.defaultBranch = body.defaultBranch if (body.dockerImage !== undefined) updateData.dockerImage = body.dockerImage if (body.envVars !== undefined) updateData.envVars = body.envVars if (body.replicas !== undefined) updateData.replicas = body.replicas if (body.cpuLimit !== undefined) updateData.cpuLimit = body.cpuLimit if (body.memoryLimit !== undefined) updateData.memoryLimit = body.memoryLimit if (body.status !== undefined) updateData.status = body.status await db .update(projects) .set(updateData) .where(eq(projects.id, projectId)) // Get updated project const updated = await db .select() .from(projects) .where(eq(projects.id, projectId)) .limit(1) return Response.json({ success: true, data: updated[0], }) } catch (error) { console.error('Error updating project:', error) return Response.json({ success: false, error: 'Failed to update project', }, { status: 500 }) } } /** * Delete project */ async function deleteProject(projectId: string): Promise { try { // Check if project exists const existing = await db .select() .from(projects) .where(eq(projects.id, projectId)) .limit(1) if (existing.length === 0) { return Response.json({ success: false, error: 'Project not found', }, { status: 404 }) } await db.delete(projects).where(eq(projects.id, projectId)) return Response.json({ success: true, message: 'Project deleted', }) } catch (error) { console.error('Error deleting project:', error) return Response.json({ success: false, error: 'Failed to delete project', }, { status: 500 }) } }