From 9cc418aa992bbcbc4b704872d1102f542c13a813 Mon Sep 17 00:00:00 2001 From: Leopoldadmin Date: Mon, 22 Jun 2026 05:51:42 +0000 Subject: [PATCH] feat: implement block management API endpoints --- backend/src/routes/blocks.ts | 123 ++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/backend/src/routes/blocks.ts b/backend/src/routes/blocks.ts index 9b7474c..2be198a 100644 --- a/backend/src/routes/blocks.ts +++ b/backend/src/routes/blocks.ts @@ -1,5 +1,122 @@ -import { FastifyInstance } from 'fastify'; +import { FastifyInstance, FastifyRequest } from 'fastify'; +import { z } from 'zod'; +import { authenticate, authorizeProjectMember, authorizePlanner } from '../middleware/auth'; +import { BlockService } from '../services/blockService'; + +const blockIdSchema = z.object({ + blockId: z.string().uuid() +}); + +const blockCreateSchema = z.object({ + name: z.string().min(1), + description: z.string().optional(), + elements: z.array(z.string().uuid()) +}); + +const blockUpdateSchema = z.object({ + name: z.string().min(1).optional(), + description: z.string().optional(), + elements: z.array(z.string().uuid()).optional() +}); + +const blockInsertSchema = z.object({ + position_x: z.number(), + position_y: z.number(), + rotation: z.number().optional().default(0), + scale_x: z.number().optional().default(1), + scale_y: z.number().optional().default(1) +}); export default async function blocksRoutes(fastify: FastifyInstance) { - // Placeholder for blocks routes -} + // GET / - List block definitions for project + fastify.get('/', { + preHandler: [authenticate, authorizeProjectMember] + }, async (request, reply) => { + try { + const projectId = request.params.projectId; + const blocks = await BlockService.listBlocks(projectId); + return blocks; + } catch (error) { + request.log.error(error); + reply.status(500).send({ error: 'Failed to list blocks' }); + } + }); + + // POST / - Create block definition from selected elements + fastify.post('/', { + preHandler: [authenticate, authorizePlanner] + }, async (request, reply) => { + try { + const projectId = request.params.projectId; + const body = blockCreateSchema.parse(request.body); + const block = await BlockService.createBlock(projectId, body); + reply.status(201).send(block); + } catch (error) { + if (error instanceof z.ZodError) { + reply.status(400).send({ error: 'Validation error', details: error.errors }); + } else { + request.log.error(error); + reply.status(500).send({ error: 'Failed to create block' }); + } + } + }); + + // PUT /:blockId - Update block definition + fastify.put('/:blockId', { + preHandler: [authenticate, authorizePlanner] + }, async (request, reply) => { + try { + const { blockId } = blockIdSchema.parse(request.params); + const projectId = request.params.projectId; + const body = blockUpdateSchema.parse(request.body); + const block = await BlockService.updateBlock(projectId, blockId, body); + return block; + } catch (error) { + if (error instanceof z.ZodError) { + reply.status(400).send({ error: 'Validation error', details: error.errors }); + } else { + request.log.error(error); + reply.status(500).send({ error: 'Failed to update block' }); + } + } + }); + + // DELETE /:blockId - Delete block definition + fastify.delete('/:blockId', { + preHandler: [authenticate, authorizePlanner] + }, async (request, reply) => { + try { + const { blockId } = blockIdSchema.parse(request.params); + const projectId = request.params.projectId; + await BlockService.deleteBlock(projectId, blockId); + reply.status(204).send(); + } catch (error) { + if (error instanceof z.ZodError) { + reply.status(400).send({ error: 'Validation error', details: error.errors }); + } else { + request.log.error(error); + reply.status(500).send({ error: 'Failed to delete block' }); + } + } + }); + + // POST /:blockId/insert - Insert block instance with parameters + fastify.post('/:blockId/insert', { + preHandler: [authenticate, authorizePlanner] + }, async (request, reply) => { + try { + const { blockId } = blockIdSchema.parse(request.params); + const projectId = request.params.projectId; + const body = blockInsertSchema.parse(request.body); + const instance = await BlockService.insertBlockInstance(projectId, blockId, body); + reply.status(201).send(instance); + } catch (error) { + if (error instanceof z.ZodError) { + reply.status(400).send({ error: 'Validation error', details: error.errors }); + } else { + request.log.error(error); + reply.status(500).send({ error: 'Failed to insert block instance' }); + } + } + }); +} \ No newline at end of file