import * as db from '../../db/categoryattributevalue.js'; import { emit } from '../sse.js'; function requireSelectedCompany(req) { const companyId = req.user?.selectedCompanyId; if (companyId == null) { return { error: 'No company selected' }; } return { companyId }; } function parsePositiveInt(value, field) { const id = Number(value); if (!Number.isInteger(id) || id <= 0) { return { error: `${field} is required` }; } return { id }; } function emitCategorySignal(req) { const companyId = req.user?.selectedCompanyId; if (companyId == null) return; emit('category', { companyId }); } function categoryAttributeValueErrorStatus(error) { if (error.message === 'No company selected') return 400; if (error.message === 'Not authorized') return 403; if (error.message === 'Company not found' || error.message === 'Category not found' || error.message === 'Parent not found') return 404; if (error.message?.startsWith('Attribute value not found')) return 404; if (error.message?.includes('exclusive')) return 400; if (error.message === 'Invalid attribute values array' || error.message === 'Invalid attributeValueId' || error.message === 'Duplicate attributeValueId') return 400; return 500; } /** * Registers categoryattributevalue routes under `/category/:id/attributevalue`. * @param {import('express').Application} app * @param {string} [basePath=''] */ export function register(app, basePath = '') { /** * @openapi * /category/{id}/attributevalue: * get: * tags: [Category] * summary: List category attribute values * description: Fetches all attribute values assigned to a category. * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Category ID * responses: * 200: * description: List of attribute values assigned to this category * content: * application/json: * schema: * type: object * properties: * attributevalues: * type: array * items: * $ref: '#/components/schemas/CategoryAttributeValue' * put: * tags: [Category] * summary: Bulk set category attribute values * description: Replaces all attribute values for a category. Enforces exclusive constraint (max one value per exclusive attribute). * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Category ID * requestBody: * required: true * content: * application/json: * schema: * type: object * required: [attributevalues] * properties: * attributevalues: * type: array * description: Array of attribute value IDs (numbers) or objects with id or attributeValueId * items: * oneOf: * - type: integer * description: Attribute value ID * - type: object * properties: * id: * type: integer * description: Attribute value ID * attributeValueId: * type: integer * description: Attribute value ID * sort: * type: integer * responses: * 200: * description: Updated category attribute values * content: * application/json: * schema: * type: object * properties: * attributevalues: * type: array * items: * $ref: '#/components/schemas/CategoryAttributeValue' */ app.get(`${basePath}/category/:id/attributevalue`, async (req, res) => { const selected = requireSelectedCompany(req); if (selected.error) { return res.status(400).json({ error: selected.error }); } const idParsed = parsePositiveInt(req.params.id, 'categoryId'); if (idParsed.error) { return res.status(400).json({ error: idParsed.error }); } try { const attributevalues = await db.listByCategoryId(req.user.id, idParsed.id); res.json({ attributevalues }); } catch (error) { res.status(categoryAttributeValueErrorStatus(error)).json({ error: error.message }); } }); app.put(`${basePath}/category/:id/attributevalue`, async (req, res) => { const selected = requireSelectedCompany(req); if (selected.error) { return res.status(400).json({ error: selected.error }); } const idParsed = parsePositiveInt(req.params.id, 'categoryId'); if (idParsed.error) { return res.status(400).json({ error: idParsed.error }); } const valuesInput = req.body?.attributevalues ?? req.body?.attributeValues ?? req.body?.attribute_values ?? req.body?.values ?? req.body; if (!Array.isArray(valuesInput)) { return res.status(400).json({ error: 'attributevalues array required' }); } try { const attributevalues = await db.setByCategoryId(req.user.id, idParsed.id, valuesInput); emitCategorySignal(req); res.json({ attributevalues }); } catch (error) { res.status(categoryAttributeValueErrorStatus(error)).json({ error: error.message }); } }); }