diff --git a/src/database/schemas/management/documenttemplate.schema.js b/src/database/schemas/management/documenttemplate.schema.js index 4b0c6b9..48e75ea 100644 --- a/src/database/schemas/management/documenttemplate.schema.js +++ b/src/database/schemas/management/documenttemplate.schema.js @@ -2,6 +2,53 @@ import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; const { Schema } = mongoose; +const RENDER_DOCUMENT_TEMPLATE_CALL = + /fc\.renderDocumentTemplate\s*\(\s*(['"])([^'"]+)\1/g; + +function extractRenderDocumentTemplateReferences(content) { + if (content == null || typeof content !== 'string' || content === '') { + return []; + } + + const references = []; + const seen = new Set(); + const regex = new RegExp(RENDER_DOCUMENT_TEMPLATE_CALL.source, 'g'); + let match; + while ((match = regex.exec(content)) !== null) { + const reference = match[2]?.trim(); + if (!reference || seen.has(reference)) { + continue; + } + seen.add(reference); + references.push(reference); + } + return references; +} + +function objectIdsFromFilterValue(value) { + if (value == null) { + return []; + } + if (value instanceof mongoose.Types.ObjectId) { + return [value]; + } + if (typeof value === 'string' && /^[a-f\d]{24}$/i.test(value)) { + return [new mongoose.Types.ObjectId(value)]; + } + if (Array.isArray(value)) { + return value.flatMap(objectIdsFromFilterValue); + } + if (typeof value === 'object') { + if (Array.isArray(value.$in)) { + return objectIdsFromFilterValue(value.$in); + } + if (value._id != null) { + return objectIdsFromFilterValue(value._id); + } + } + return []; +} + const documentTemplateSchema = new Schema( { _reference: { type: String, default: () => generateId()() }, @@ -39,6 +86,13 @@ const documentTemplateSchema = new Schema( required: false, }, ], + referencedTemplates: [ + { + type: Schema.Types.ObjectId, + ref: 'documentTemplate', + required: false, + }, + ], content: { type: String, required: false, @@ -63,4 +117,50 @@ documentTemplateSchema.virtual('id').get(function () { // Configure JSON serialization to include virtuals documentTemplateSchema.set('toJSON', { virtuals: true }); +documentTemplateSchema.statics.recalculate = async function (documentTemplate, user) { + const documentTemplateId = documentTemplate?._id || documentTemplate; + if (!documentTemplateId) { + return; + } + + const stillExists = await this.exists({ _id: documentTemplateId }); + if (!stillExists) { + return; + } + + const { getFilter } = await import('../../../utils.js'); + const references = extractRenderDocumentTemplateReferences(documentTemplate?.content); + const referencedTemplateIds = []; + const seenIds = new Set(); + + for (const reference of references) { + const filter = await getFilter({ parent: reference }, ['parent'], true, this); + const ids = objectIdsFromFilterValue(filter.parent); + for (const id of ids) { + const idString = String(id); + if (!idString || seenIds.has(idString)) { + continue; + } + seenIds.add(idString); + referencedTemplateIds.push(id); + } + } + + if (documentTemplate && typeof documentTemplate === 'object' && !documentTemplate._bsontype) { + documentTemplate.referencedTemplates = referencedTemplateIds.map((id) => ({ + _id: String(id), + })); + } + + const { editObject } = await import('../../database.js'); + await editObject({ + model: this, + id: documentTemplateId, + updateData: { referencedTemplates: referencedTemplateIds }, + user, + populate: [{ path: 'referencedTemplates', strictPopulate: false }], + recalculate: false, + }); +}; + export const documentTemplateModel = mongoose.model('documentTemplate', documentTemplateSchema); diff --git a/src/routes/management/documenttemplates.js b/src/routes/management/documenttemplates.js index 5ed5626..ec128d7 100644 --- a/src/routes/management/documenttemplates.js +++ b/src/routes/management/documenttemplates.js @@ -14,6 +14,8 @@ const listAllowedFilters = [ 'parent._id', 'documentSize', 'documentSize._id', + 'referencedTemplates', + 'referencedTemplates._id', 'objectType', 'createdAt', 'updatedAt', diff --git a/src/services/management/documenttemplates.js b/src/services/management/documenttemplates.js index 2e37971..a680920 100644 --- a/src/services/management/documenttemplates.js +++ b/src/services/management/documenttemplates.js @@ -71,6 +71,7 @@ export const listDocumentTemplatesRouteHandler = async ( { path: 'documentSize' }, { path: 'parent' }, { path: 'documentPrinters', strictPopulate: false }, + { path: 'referencedTemplates', strictPopulate: false }, ], }); @@ -136,6 +137,7 @@ export const getDocumentTemplateRouteHandler = async (req, res) => { { path: 'documentSize' }, { path: 'parent', strictPopulate: false }, { path: 'documentPrinters', strictPopulate: false }, + { path: 'referencedTemplates', strictPopulate: false }, { path: 'testObject', strictPopulate: false }, ], }); @@ -186,6 +188,7 @@ export const editDocumentTemplateRouteHandler = async (req, res) => { { path: 'documentSize' }, { path: 'parent', strictPopulate: false }, { path: 'documentPrinters', strictPopulate: false }, + { path: 'referencedTemplates', strictPopulate: false }, { path: 'testObject', strictPopulate: false }, ], });