u
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { validateObjects } from 'react-canvas-label-editor';
|
||||
import * as db from '../../db/labeltemplate.js';
|
||||
import { renderThumb } from '../../services/labelThumb.js';
|
||||
import { emit } from '../sse.js';
|
||||
@@ -29,6 +30,7 @@ function labeltemplateErrorStatus(error) {
|
||||
if (error.message?.startsWith('Invalid dpi')) return 400;
|
||||
if (error.message?.startsWith('Invalid type')) return 400;
|
||||
if (error.message === 'Content required') return 400;
|
||||
if (error.message?.startsWith('Invalid label objects')) return 400;
|
||||
return 500;
|
||||
}
|
||||
|
||||
@@ -209,8 +211,13 @@ export function register(app, basePath = '') {
|
||||
|
||||
const { name, width, height, dpi, type, content } = req.body ?? {};
|
||||
|
||||
const validation = validateLabelContent(content);
|
||||
if (!validation.valid) {
|
||||
return res.status(400).json({ error: validation.error, ...(validation.errors ? { errors: validation.errors } : {}) });
|
||||
}
|
||||
|
||||
try {
|
||||
const thumb = await buildThumb({ width, height, content });
|
||||
const thumb = await buildThumb({ width, height, content, objects: validation.objects });
|
||||
const template = await db.create(req.user.id, {
|
||||
name,
|
||||
width,
|
||||
@@ -242,9 +249,18 @@ export function register(app, basePath = '') {
|
||||
|
||||
const { name, width, height, dpi, type, content } = req.body ?? {};
|
||||
|
||||
let validatedObjects;
|
||||
if (content !== undefined) {
|
||||
const validation = validateLabelContent(content);
|
||||
if (!validation.valid) {
|
||||
return res.status(400).json({ error: validation.error, ...(validation.errors ? { errors: validation.errors } : {}) });
|
||||
}
|
||||
validatedObjects = validation.objects;
|
||||
}
|
||||
|
||||
try {
|
||||
// Re-render thumb whenever content/dimensions are provided
|
||||
const thumb = await buildThumb({ width, height, content });
|
||||
const thumb = await buildThumb({ width, height, content, objects: validatedObjects });
|
||||
const template = await db.update(req.user.id, parsedId.id, {
|
||||
name,
|
||||
width,
|
||||
@@ -445,6 +461,45 @@ function serializeTemplate(template) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the label template content and its objects.
|
||||
* Expects content to be an object with an `objects` array (or an array of objects).
|
||||
*
|
||||
* @param {any} content
|
||||
* @returns {{ valid: true, objects: Array } | { valid: false, error: string, errors?: string[] }}
|
||||
*/
|
||||
function validateLabelContent(content) {
|
||||
if (content == null) {
|
||||
return { valid: false, error: 'Content required' };
|
||||
}
|
||||
|
||||
let parsed = content;
|
||||
if (typeof content === 'string') {
|
||||
try {
|
||||
parsed = JSON.parse(content);
|
||||
} catch {
|
||||
return { valid: false, error: 'Invalid JSON in content' };
|
||||
}
|
||||
}
|
||||
|
||||
const objects = Array.isArray(parsed?.objects)
|
||||
? parsed.objects
|
||||
: Array.isArray(parsed)
|
||||
? parsed
|
||||
: null;
|
||||
|
||||
if (!objects) {
|
||||
return { valid: false, error: 'content.objects must be an array' };
|
||||
}
|
||||
|
||||
const { valid, errors } = validateObjects(objects);
|
||||
if (!valid) {
|
||||
return { valid: false, error: `Invalid label objects: ${errors.join(', ')}`, errors };
|
||||
}
|
||||
|
||||
return { valid: true, objects };
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to render a thumbnail from content + dimensions.
|
||||
* Returns null silently if content or dimensions are missing/invalid —
|
||||
@@ -452,18 +507,20 @@ function serializeTemplate(template) {
|
||||
*
|
||||
* @returns {Promise<Buffer|null>}
|
||||
*/
|
||||
async function buildThumb({ width, height, content }) {
|
||||
async function buildThumb({ width, height, content, objects: passedObjects }) {
|
||||
try {
|
||||
if (content == null) return null;
|
||||
if (content == null && passedObjects == null) return null;
|
||||
const w = Number(width);
|
||||
const h = Number(height);
|
||||
if (!Number.isInteger(w) || w <= 0 || !Number.isInteger(h) || h <= 0) return null;
|
||||
|
||||
const objects = Array.isArray(content?.objects)
|
||||
? content.objects
|
||||
: Array.isArray(content)
|
||||
? content
|
||||
: [];
|
||||
const objects = passedObjects ?? (
|
||||
Array.isArray(content?.objects)
|
||||
? content.objects
|
||||
: Array.isArray(content)
|
||||
? content
|
||||
: []
|
||||
);
|
||||
|
||||
return await renderThumb({ width: w, height: h, objects });
|
||||
} catch {
|
||||
@@ -471,3 +528,4 @@ async function buildThumb({ width, height, content }) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user