From a463b67bce9c3577ab14afdb3b59e4914d7979ea Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Tue, 7 Apr 2026 21:58:28 -0400 Subject: [PATCH] add services/mam-api/src/routes/bins.js --- services/mam-api/src/routes/bins.js | 179 ++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 services/mam-api/src/routes/bins.js diff --git a/services/mam-api/src/routes/bins.js b/services/mam-api/src/routes/bins.js new file mode 100644 index 0000000..94c6063 --- /dev/null +++ b/services/mam-api/src/routes/bins.js @@ -0,0 +1,179 @@ +import express from 'express'; +import pool from '../db/pool.js'; +import { requireAuth } from '../middleware/auth.js'; +import { v4 as uuidv4 } from 'uuid'; + +const router = express.Router(); + +router.use(requireAuth); + +// GET / - List bins for a project_id +router.get('/', async (req, res, next) => { + try { + const { project_id } = req.query; + + if (!project_id) { + return res.status(400).json({ error: 'project_id is required' }); + } + + const result = await pool.query( + `SELECT * FROM bins WHERE project_id = $1 ORDER BY created_at DESC`, + [project_id] + ); + + res.json(result.rows); + } catch (err) { + next(err); + } +}); + +// POST / - Create bin +router.post('/', async (req, res, next) => { + try { + const { project_id, name, parent_id } = req.body; + + if (!project_id || !name) { + return res.status(400).json({ error: 'project_id and name are required' }); + } + + const id = uuidv4(); + + const result = await pool.query( + `INSERT INTO bins (id, project_id, name, parent_id, created_at, updated_at) + VALUES ($1, $2, $3, $4, NOW(), NOW()) + RETURNING *`, + [id, project_id, name, parent_id || null] + ); + + res.status(201).json(result.rows[0]); + } catch (err) { + next(err); + } +}); + +// PATCH /:id - Update bin +router.patch('/:id', async (req, res, next) => { + try { + const { id } = req.params; + const { name, parent_id } = req.body; + + const updates = []; + const params = []; + let paramCount = 1; + + if (name !== undefined) { + updates.push(`name = $${paramCount++}`); + params.push(name); + } + + if (parent_id !== undefined) { + updates.push(`parent_id = $${paramCount++}`); + params.push(parent_id || null); + } + + if (updates.length === 0) { + return res.status(400).json({ error: 'No fields to update' }); + } + + updates.push(`updated_at = NOW()`); + params.push(id); + + const query = ` + UPDATE bins + SET ${updates.join(', ')} + WHERE id = $${paramCount} + RETURNING * + `; + + const result = await pool.query(query, params); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Bin not found' }); + } + + res.json(result.rows[0]); + } catch (err) { + next(err); + } +}); + +// DELETE /:id - Delete bin +router.delete('/:id', async (req, res, next) => { + try { + const { id } = req.params; + + const result = await pool.query( + 'DELETE FROM bins WHERE id = $1 RETURNING *', + [id] + ); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Bin not found' }); + } + + res.json({ message: 'Bin deleted', bin: result.rows[0] }); + } catch (err) { + next(err); + } +}); + +// POST /:id/assets - Add asset to bin +router.post('/:id/assets', async (req, res, next) => { + try { + const { id } = req.params; + const { asset_id } = req.body; + + if (!asset_id) { + return res.status(400).json({ error: 'asset_id is required' }); + } + + // Verify bin exists + const binCheck = await pool.query('SELECT id FROM bins WHERE id = $1', [id]); + if (binCheck.rows.length === 0) { + return res.status(404).json({ error: 'Bin not found' }); + } + + // Update asset's bin_id + const result = await pool.query( + 'UPDATE assets SET bin_id = $1, updated_at = NOW() WHERE id = $2 RETURNING *', + [id, asset_id] + ); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Asset not found' }); + } + + res.json(result.rows[0]); + } catch (err) { + next(err); + } +}); + +// DELETE /:id/assets/:assetId - Remove asset from bin +router.delete('/:id/assets/:assetId', async (req, res, next) => { + try { + const { id, assetId } = req.params; + + // Verify bin exists + const binCheck = await pool.query('SELECT id FROM bins WHERE id = $1', [id]); + if (binCheck.rows.length === 0) { + return res.status(404).json({ error: 'Bin not found' }); + } + + // Remove asset from bin + const result = await pool.query( + 'UPDATE assets SET bin_id = NULL, updated_at = NOW() WHERE id = $1 AND bin_id = $2 RETURNING *', + [assetId, id] + ); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Asset not found in this bin' }); + } + + res.json({ message: 'Asset removed from bin', asset: result.rows[0] }); + } catch (err) { + next(err); + } +}); + +export default router;