This commit introduces new padding options for document sizes, allowing for customizable print padding and specific padding values (left, right, top, bottom). The document size schema has been updated to include these new fields, and corresponding route handlers have been modified to handle padding data during document size creation and editing. Additionally, the template manager has been updated to apply padding when rendering templates, ensuring that the layout respects the specified padding values. Tests have been added to verify the correct application of padding in both document sizes and templates, improving the overall document formatting capabilities.
385 lines
10 KiB
JavaScript
385 lines
10 KiB
JavaScript
import config from '../../config.js';
|
|
import { documentTemplateModel } from '../../database/schemas/management/documenttemplate.schema.js';
|
|
import log4js from 'log4js';
|
|
import mongoose from 'mongoose';
|
|
import {
|
|
deleteObject,
|
|
listObjects,
|
|
getObject,
|
|
editObject,
|
|
newObject,
|
|
listObjectsByProperties,
|
|
getModelStats,
|
|
getModelHistory,
|
|
searchObjects,
|
|
getPropertyValues,
|
|
getObjectNeighbors,
|
|
} from '../../database/database.js';
|
|
import { templateManager } from '../../templates/templatemanager.js';
|
|
import { formatTemplateContent } from '../../templates/templateformatter.js';
|
|
const logger = log4js.getLogger('Document Templates');
|
|
logger.level = config.server.logLevel;
|
|
|
|
function parseOptionalBoolean(value) {
|
|
if (value === undefined || value === null || value === '') {
|
|
return undefined;
|
|
}
|
|
if (value === true || value === false) {
|
|
return value;
|
|
}
|
|
const lower = String(value).trim().toLowerCase();
|
|
if (lower === 'true' || lower === '1') {
|
|
return true;
|
|
}
|
|
if (lower === 'false' || lower === '0') {
|
|
return false;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function getPaddingOption(req, defaultValue = true) {
|
|
return parseOptionalBoolean(req.body?.padding ?? req.query?.padding) ?? defaultValue;
|
|
}
|
|
|
|
export const listDocumentTemplatesRouteHandler = async (
|
|
req,
|
|
res,
|
|
page = 1,
|
|
limit = 25,
|
|
property = '',
|
|
filter = {},
|
|
search = '',
|
|
sort = '',
|
|
order = 'ascend'
|
|
) => {
|
|
const result = await listObjects({
|
|
model: documentTemplateModel,
|
|
page,
|
|
limit,
|
|
property,
|
|
filter,
|
|
search,
|
|
sort,
|
|
order,
|
|
populate: [
|
|
{ path: 'documentSize' },
|
|
{ path: 'parent' },
|
|
{ path: 'documentPrinters', strictPopulate: false },
|
|
],
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing document templates.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(
|
|
`List of document templates (Page ${page}, Limit ${limit}). Count: ${result.length}`
|
|
);
|
|
res.send(result);
|
|
};
|
|
|
|
export const listDocumentTemplatesByPropertiesRouteHandler = async (
|
|
req,
|
|
res,
|
|
properties = '',
|
|
filter = {},
|
|
masterFilter = {}
|
|
) => {
|
|
const result = await listObjectsByProperties({
|
|
model: documentTemplateModel,
|
|
properties,
|
|
filter,
|
|
populate: ['documentSize'],
|
|
masterFilter,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing document templates.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`List of document templates. Count: ${result.length}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getDocumentTemplatePropertyValuesRouteHandler = async (req, res, property) => {
|
|
const result = await getPropertyValues({
|
|
model: documentTemplateModel,
|
|
property,
|
|
});
|
|
res.send(result);
|
|
};
|
|
|
|
export const searchDocumentTemplatesRouteHandler = async (req, res, search) => {
|
|
const result = await searchObjects({
|
|
model: documentTemplateModel,
|
|
search,
|
|
});
|
|
res.send(result);
|
|
};
|
|
|
|
export const getDocumentTemplateRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const result = await getObject({
|
|
model: documentTemplateModel,
|
|
id,
|
|
populate: [
|
|
{ path: 'documentSize' },
|
|
{ path: 'parent', strictPopulate: false },
|
|
{ path: 'documentPrinters', strictPopulate: false },
|
|
],
|
|
});
|
|
if (result?.error) {
|
|
logger.warn(`Document Template not found with supplied id.`);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.debug(`Retreived document template with ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const editDocumentTemplateRouteHandler = async (req, res) => {
|
|
// Get ID from params
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`Document Template with ID: ${id}`);
|
|
|
|
let formattedContent = req.body.content;
|
|
if (req.body.content != null && typeof req.body.content === 'string') {
|
|
const formatResult = formatTemplateContent(req.body.content);
|
|
if (formatResult?.error) {
|
|
logger.warn('Error formatting document template content:', formatResult.error);
|
|
return res.status(formatResult.code || 400).send(formatResult);
|
|
}
|
|
formattedContent = formatResult.content;
|
|
}
|
|
|
|
const updateData = {
|
|
updatedAt: new Date(),
|
|
name: req.body.name,
|
|
tags: req.body.tags,
|
|
active: req.body.active,
|
|
global: req.body.global,
|
|
parent: req.body.parent,
|
|
objectType: req.body.objectType,
|
|
documentSize: req.body.documentSize,
|
|
documentPrinters: req.body.documentPrinters,
|
|
content: formattedContent,
|
|
testObject: req.body.testObject,
|
|
};
|
|
// Create audit log before updating
|
|
const result = await editObject({
|
|
model: documentTemplateModel,
|
|
id,
|
|
updateData,
|
|
user: req.user,
|
|
populate: [
|
|
{ path: 'documentSize' },
|
|
{ path: 'parent', strictPopulate: false },
|
|
{ path: 'documentPrinters', strictPopulate: false },
|
|
],
|
|
});
|
|
|
|
if (result.error) {
|
|
logger.error('Error editing document template:', result.error);
|
|
res.status(result).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`Edited document template with ID: ${id}`);
|
|
|
|
res.send(result);
|
|
};
|
|
|
|
export const newDocumentTemplateRouteHandler = async (req, res) => {
|
|
const newData = {
|
|
updatedAt: new Date(),
|
|
name: req.body.name,
|
|
tags: req.body.tags,
|
|
active: req.body.active,
|
|
global: req.body.global,
|
|
parent: req.body.parent,
|
|
objectType: req.body.objectType,
|
|
documentSize: req.body.documentSize,
|
|
documentPrinters: req.body.documentPrinters,
|
|
content: req.body.content,
|
|
};
|
|
const result = await newObject({
|
|
model: documentTemplateModel,
|
|
newData,
|
|
user: req.user,
|
|
});
|
|
if (result.error) {
|
|
logger.error('No document template created:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`New document template with ID: ${result._id}`);
|
|
|
|
res.send(result);
|
|
};
|
|
|
|
export const deleteDocumentTemplateRouteHandler = async (req, res) => {
|
|
// Get ID from params
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`Document Template with ID: ${id}`);
|
|
|
|
const result = await deleteObject({
|
|
model: documentTemplateModel,
|
|
id,
|
|
user: req.user,
|
|
});
|
|
if (result.error) {
|
|
logger.error('No document template deleted:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`Deleted document template with ID: ${result._id}`);
|
|
|
|
res.send(result);
|
|
};
|
|
|
|
export const getDocumentTemplateStatsRouteHandler = async (req, res) => {
|
|
const result = await getModelStats({ model: documentTemplateModel });
|
|
if (result?.error) {
|
|
logger.error('Error fetching document template stats:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('Document template stats:', result);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getDocumentTemplateHistoryRouteHandler = async (req, res) => {
|
|
const from = req.query.from;
|
|
const to = req.query.to;
|
|
const result = await getModelHistory({ model: documentTemplateModel, from, to });
|
|
if (result?.error) {
|
|
logger.error('Error fetching document template history:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('Document template history:', result);
|
|
res.send(result);
|
|
};
|
|
export const getDocumentTemplateNeighborsRouteHandler = async (
|
|
req,
|
|
res,
|
|
property = '',
|
|
filter = {},
|
|
search = '',
|
|
sort = '',
|
|
order = 'ascend',
|
|
id
|
|
) => {
|
|
if (!id) {
|
|
return res.status(400).send({ error: 'Missing id parameter', code: 400 });
|
|
}
|
|
|
|
const result = await getObjectNeighbors({
|
|
model: documentTemplateModel,
|
|
id,
|
|
filter,
|
|
search,
|
|
sort,
|
|
order,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error fetching documentTemplate neighbors.');
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`Retrieved documentTemplate neighbors for ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const formatDocumentTemplateRouteHandler = async (req, res) => {
|
|
const content = req.body?.content;
|
|
|
|
logger.debug('Formatting document template content');
|
|
|
|
const result = formatTemplateContent(content);
|
|
if (result?.error) {
|
|
logger.warn('Error formatting document template content:', result.error);
|
|
return res.status(result.code || 400).send(result);
|
|
}
|
|
|
|
res.send({ content: result.content });
|
|
};
|
|
|
|
export const previewDocumentTemplateRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const content = req.body?.content;
|
|
const testObject = req.body?.testObject || req.body?.object || {};
|
|
const scale = req.body?.scale ?? 1;
|
|
const padding = getPaddingOption(req, true);
|
|
|
|
logger.debug(`Previewing document template with ID: ${id}`);
|
|
|
|
const result = await templateManager.renderTemplate(
|
|
id,
|
|
content,
|
|
testObject,
|
|
scale,
|
|
{ padding },
|
|
true
|
|
);
|
|
|
|
if (result?.error) {
|
|
logger.warn('Error previewing document template:', result.error);
|
|
return res.status(result.code || 400).send(result);
|
|
}
|
|
|
|
res.send(result);
|
|
};
|
|
|
|
export const downloadDocumentTemplateRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const type = req.query.type || req.body?.type || 'pdf';
|
|
const content = req.body?.content;
|
|
const data = req.body?.object || req.body?.testObject || {};
|
|
const width = req.body?.width || req.query.width;
|
|
const filename = req.body?.filename || req.query.filename || 'document';
|
|
const options = {
|
|
padding: getPaddingOption(req, true),
|
|
};
|
|
if (width) {
|
|
options.width = Number(width);
|
|
}
|
|
|
|
logger.debug(`Downloading document template ${id} as ${type}`);
|
|
|
|
const result = await templateManager.renderDownload(id, content, data, type, options);
|
|
|
|
if (result?.error) {
|
|
logger.warn('Error downloading document template:', result.error);
|
|
return res.status(result.code || 400).send(result);
|
|
}
|
|
|
|
const buffers = result.buffers || [];
|
|
if (buffers.length === 0) {
|
|
return res.status(500).send({ error: 'Failed to render document template.' });
|
|
}
|
|
|
|
if (buffers.length === 1) {
|
|
const buffer = buffers[0];
|
|
res.set('Content-Type', result.mime);
|
|
res.set(
|
|
'Content-Disposition',
|
|
`attachment; filename="${filename}.${result.extension}"`
|
|
);
|
|
res.set('Content-Length', String(buffer.length));
|
|
return res.send(buffer);
|
|
}
|
|
|
|
res.send({
|
|
type: result.type,
|
|
mime: result.mime,
|
|
extension: result.extension,
|
|
images: buffers.map((buffer) => Buffer.from(buffer).toString('base64')),
|
|
});
|
|
};
|
|
|