Add resource management to document and email template schemas
All checks were successful
farmcontrol/farmcontrol-ws/pipeline/head This commit looks good

- Introduced a `resources` field in both `documentTemplate` and `emailTemplate` schemas to manage associated resources.
- Implemented validation and normalization functions for resource names to ensure uniqueness and proper formatting.
- Updated schemas to include resource name and file references, enhancing template management capabilities.
This commit is contained in:
Tom Butcher 2026-09-13 19:51:28 +01:00
parent 110ea9355a
commit cd12a0ca0d
2 changed files with 96 additions and 5 deletions

View File

@ -2,8 +2,33 @@ import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
const RENDER_DOCUMENT_TEMPLATE_CALL = const RESOURCE_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
/fc\.renderDocumentTemplate\s*\(\s*(['"])([^'"]+)\1/g;
function normalizeTemplateResourceName(value) {
return String(value ?? '')
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function validateTemplateResources(resources) {
const names = new Set();
for (const resource of resources || []) {
if (
!RESOURCE_NAME_PATTERN.test(resource?.name || '') ||
resource?.file == null ||
resource.file === '' ||
names.has(resource.name)
) {
return false;
}
names.add(resource.name);
}
return true;
}
const RENDER_DOCUMENT_TEMPLATE_CALL = /fc\.renderDocumentTemplate\s*\(\s*(['"])([^'"]+)\1/g;
function extractRenderDocumentTemplateReferences(content) { function extractRenderDocumentTemplateReferences(content) {
if (content == null || typeof content !== 'string' || content === '') { if (content == null || typeof content !== 'string' || content === '') {
@ -103,6 +128,27 @@ const documentTemplateSchema = new Schema(
refPath: 'objectType', refPath: 'objectType',
required: false, required: false,
}, },
resources: {
type: [
new Schema(
{
name: {
type: String,
required: true,
set: normalizeTemplateResourceName,
match: RESOURCE_NAME_PATTERN,
},
file: { type: Schema.Types.ObjectId, ref: 'file', required: true },
},
{ _id: true }
),
],
default: [],
validate: {
validator: validateTemplateResources,
message: 'Template resource names must be unique.',
},
},
}, },
{ timestamps: true } { timestamps: true }
); );

View File

@ -2,6 +2,32 @@ import mongoose from 'mongoose';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
const { Schema } = mongoose; const { Schema } = mongoose;
const RESOURCE_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
function normalizeTemplateResourceName(value) {
return String(value ?? '')
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function validateTemplateResources(resources) {
const names = new Set();
for (const resource of resources || []) {
if (
!RESOURCE_NAME_PATTERN.test(resource?.name || '') ||
resource?.file == null ||
resource.file === '' ||
names.has(resource.name)
) {
return false;
}
names.add(resource.name);
}
return true;
}
const RENDER_EMAIL_TEMPLATE_CALL = /fc\.renderEmailTemplate\s*\(\s*(['"])([^'"]+)\1/g; const RENDER_EMAIL_TEMPLATE_CALL = /fc\.renderEmailTemplate\s*\(\s*(['"])([^'"]+)\1/g;
function extractReferences(content) { function extractReferences(content) {
@ -36,13 +62,32 @@ const emailTemplateSchema = new Schema(
active: { type: Boolean, required: true, default: true }, active: { type: Boolean, required: true, default: true },
global: { type: Boolean, required: true, default: false }, global: { type: Boolean, required: true, default: false },
parent: { type: Schema.Types.ObjectId, ref: 'emailTemplate', required: false }, parent: { type: Schema.Types.ObjectId, ref: 'emailTemplate', required: false },
referencedTemplates: [ referencedTemplates: [{ type: Schema.Types.ObjectId, ref: 'emailTemplate', required: false }],
{ type: Schema.Types.ObjectId, ref: 'emailTemplate', required: false },
],
subject: { type: String, required: false, default: '' }, subject: { type: String, required: false, default: '' },
content: { type: String, required: false, default: '<Container></Container>' }, content: { type: String, required: false, default: '<Container></Container>' },
testObject: { type: Schema.Types.ObjectId, refPath: 'objectType', required: false }, testObject: { type: Schema.Types.ObjectId, refPath: 'objectType', required: false },
attachments: { type: [emailTemplateAttachmentSchema], default: [] }, attachments: { type: [emailTemplateAttachmentSchema], default: [] },
resources: {
type: [
new Schema(
{
name: {
type: String,
required: true,
set: normalizeTemplateResourceName,
match: RESOURCE_NAME_PATTERN,
},
file: { type: Schema.Types.ObjectId, ref: 'file', required: true },
},
{ _id: true }
),
],
default: [],
validate: {
validator: validateTemplateResources,
message: 'Template resource names must be unique.',
},
},
}, },
{ timestamps: true } { timestamps: true }
); );