feat(templates): persist reusable content requirements

This commit is contained in:
2026-08-19 21:54:54 +02:00
parent 1c12359750
commit 5de54ccd2e
3 changed files with 30 additions and 3 deletions
+15 -1
View File
@@ -146,7 +146,16 @@ class SqlTemplateContentLibrary(TemplateContentLibraryProvider):
template_type=request.template_type, template_type=request.template_type,
usages=list(request.usages), usages=list(request.usages),
locale=request.locale, locale=request.locale,
required_fields=[], required_fields=[
{
"path": field.path,
"value_type": field.value_type,
"label": field.label,
"required": field.required,
"description": field.description,
}
for field in request.required_fields
],
output_profiles=[], output_profiles=[],
content_text=request.content_text, content_text=request.content_text,
content_html=request.content_html, content_html=request.content_html,
@@ -168,6 +177,11 @@ class SqlTemplateContentLibrary(TemplateContentLibraryProvider):
"definition_hash": revision.definition_hash, "definition_hash": revision.definition_hash,
"template_type": revision.template_type, "template_type": revision.template_type,
"usages": list(revision.usages or []), "usages": list(revision.usages or []),
"required_fields": [
str(field.get("path") or "")
for field in revision.required_fields or []
if field.get("path")
],
"source": "content_library_capability", "source": "content_library_capability",
}, },
commit=False, commit=False,
+4 -2
View File
@@ -104,7 +104,8 @@ DOCUMENTATION = (
body=( body=(
"Content fragments retain text and HTML variants, usage constraints, locale, scope, revision, and publication state in Templates. " "Content fragments retain text and HTML variants, usage constraints, locale, scope, revision, and publication state in Templates. "
"Campaign can load a fragment or complete email part through the optional content-library capability. Saving from Campaign creates " "Campaign can load a fragment or complete email part through the optional content-library capability. Saving from Campaign creates "
"a draft and never publishes it automatically. Inserting content changes only the current Campaign draft; existing Campaign versions " "a draft with its declared required-field contract and never publishes it automatically. Consumers show missing required fields before "
"applying content. Inserting content changes only the current Campaign draft; existing Campaign versions "
"and Template revisions remain unchanged." "and Template revisions remain unchanged."
), ),
layer="available", layer="available",
@@ -118,7 +119,8 @@ DOCUMENTATION = (
"body": ( "body": (
"Inhaltsbausteine speichern Text- und HTML-Fassungen, Verwendungszwecke, Sprache, Geltungsbereich, Revision und " "Inhaltsbausteine speichern Text- und HTML-Fassungen, Verwendungszwecke, Sprache, Geltungsbereich, Revision und "
"Veröffentlichungsstatus in Templates. Campaign kann Bausteine oder vollständige E-Mail-Teile über die optionale " "Veröffentlichungsstatus in Templates. Campaign kann Bausteine oder vollständige E-Mail-Teile über die optionale "
"Inhaltsbibliothek laden. Das Speichern aus Campaign legt einen Entwurf an und veröffentlicht ihn niemals automatisch. " "Inhaltsbibliothek laden. Das Speichern aus Campaign legt einen Entwurf mit dem deklarierten Pflichtfeldvertrag an und "
"veröffentlicht ihn niemals automatisch. Fehlende Pflichtfelder werden vor dem Anwenden angezeigt. "
"Das Einfügen ändert nur den aktuellen Kampagnenentwurf; bestehende Kampagnenversionen und Template-Revisionen bleiben unverändert." "Das Einfügen ändert nur den aktuellen Kampagnenentwurf; bestehende Kampagnenversionen und Template-Revisionen bleiben unverändert."
), ),
} }
+11
View File
@@ -13,6 +13,7 @@ from govoplan_core.core.templates import (
CAPABILITY_TEMPLATE_RENDERER, CAPABILITY_TEMPLATE_RENDERER,
TemplateCompatibilityError, TemplateCompatibilityError,
TemplateContentDraftRequest, TemplateContentDraftRequest,
TemplateFieldRequirement,
TemplateRenderError, TemplateRenderError,
TemplateRenderRequest, TemplateRenderRequest,
) )
@@ -182,6 +183,12 @@ class TemplateServiceTests(unittest.TestCase):
usages=("campaign.content",), usages=("campaign.content",),
locale="de", locale="de",
content_text="Mit freundlichen Grüßen", content_text="Mit freundlichen Grüßen",
required_fields=(
TemplateFieldRequirement(
path="local.display_name",
label="Display name",
),
),
metadata={"campaign_targets": ["text"]}, metadata={"campaign_targets": ["text"]},
), ),
) )
@@ -190,6 +197,10 @@ class TemplateServiceTests(unittest.TestCase):
self.assertEqual("draft", result.status) self.assertEqual("draft", result.status)
self.assertEqual("content_fragment", result.template_type) self.assertEqual("content_fragment", result.template_type)
self.assertEqual("Mit freundlichen Grüßen", result.revision.content_text) self.assertEqual("Mit freundlichen Grüßen", result.revision.content_text)
self.assertEqual(
"local.display_name",
result.revision.required_fields[0].path,
)
self.assertEqual(["text"], result.revision.metadata["campaign_targets"]) self.assertEqual(["text"], result.revision.metadata["campaign_targets"])
self.assertEqual( self.assertEqual(
"templates.content_library", "templates.content_library",