Documentation
¶
Overview ¶
Package template defines the notification template entity with i18n support.
Index ¶
- Constants
- Variables
- func Explain(tmpl *Template, locale string) ([]Step, *Version)
- func Resolve(tmpl *Template, locale string) (*Version, Match)
- type Content
- type Diagnostic
- type FieldOutput
- type Match
- type PreviewResult
- type RenderedContent
- type Renderer
- func (r *Renderer) FuncNames() []string
- func (r *Renderer) Preview(c Content, vars []Variable, data map[string]any) *PreviewResult
- func (r *Renderer) Render(tmpl *Template, locale string, data map[string]any) (*RenderedContent, error)
- func (r *Renderer) RenderVersion(version *Version, vars []Variable, data map[string]any) (*RenderedContent, error)
- type Step
- type Store
- type Template
- type Variable
- type Version
Constants ¶
const ( SeverityError = "error" SeverityWarning = "warning" KindParse = "parse" KindExec = "exec" KindEscape = "escape" KindMissing = "missing" KindUndeclared = "undeclared" KindUnprovided = "unprovided" )
Diagnostic severities and kinds.
const ( CategoryAuth = "auth" CategoryTransactional = "transactional" CategoryMarketing = "marketing" CategorySystem = "system" )
Category constants for template organization.
const MaxBuiltFieldBytes = 4 * MaxRenderedFieldBytes
MaxBuiltFieldBytes is the most the string-building functions (print, printf, println, html, js, urlquery and the string helpers) may build in total while one field renders. Capping each result alone isn't enough: a template can keep many results alive in variables without writing them.
These limits cover output and the strings templates build, not the data a render is given. html/template's contextual escapers (jsvalescaper, attrescaper, urlnormalizer, cssvaluefilter and the rest) build their escaped copy of a data value before the capped write refuses it, so a 50 MB value in <script>var v={{.b}}</script> can allocate gigabytes. What bounds that today is outside this package: templates.render caps the whole request at maxRenderBytes (256 KiB, extension/contract), and Send's data comes from application code. A new caller that hands Preview or RenderVersion untrusted data must cap that data itself.
const MaxRenderedFieldBytes = 1 << 20
MaxRenderedFieldBytes is the most one rendered field (subject, HTML, text or title) may produce. A loop such as {{range 100000000000}} would otherwise grow the output until the process runs out of memory.
Variables ¶
var ( ErrNoVersionForLocale = errors.New("herald: no template version for locale") ErrTemplateRenderFailed = errors.New("herald: template rendering failed") ErrMissingRequiredVariable = errors.New("herald: missing required template variable") ErrRenderedTooLarge = errors.New("herald: rendered template is over the size limit") )
Renderer errors.
Functions ¶
Types ¶
type Content ¶
type Content struct {
Subject string `json:"subject"`
HTML string `json:"html"`
Text string `json:"text"`
Title string `json:"title"`
}
Content is the editable text of one version: a saved version or an unsaved editor buffer.
type Diagnostic ¶
type Diagnostic struct {
Field string `json:"field"`
Line int `json:"line"`
Column int `json:"column"`
Severity string `json:"severity"`
Kind string `json:"kind"`
Message string `json:"message"`
}
Diagnostic is one problem found while previewing a template. Positions are 1-based; a zero Line or Column means Go did not report one.
type FieldOutput ¶
type FieldOutput struct {
Field string `json:"field"`
Output string `json:"output"`
Rendered bool `json:"rendered"`
}
FieldOutput is one field's rendered text. Rendered is false when the field was empty or failed.
type PreviewResult ¶
type PreviewResult struct {
Fields []FieldOutput `json:"fields"`
Diagnostics []Diagnostic `json:"diagnostics"`
}
PreviewResult is every field's output and every problem found.
type RenderedContent ¶
RenderedContent holds the fully rendered template output.
type Renderer ¶
type Renderer struct {
// contains filtered or unexported fields
}
Renderer processes Go templates with data to produce rendered notification content.
func NewRenderer ¶
func NewRenderer() *Renderer
NewRenderer creates a new template renderer with default helper functions.
func (*Renderer) Preview ¶
Preview renders every field of c independently against data, with variable defaults applied, and reports every problem as a Diagnostic. It never returns an error and never stops at the first failure, so a broken HTML body doesn't hide a broken subject. Nothing is sent.
func (*Renderer) Render ¶
func (r *Renderer) Render(tmpl *Template, locale string, data map[string]any) (*RenderedContent, error)
Render renders the version that answers locale (see Resolve) with data, after filling declared defaults. It stops at the first field that fails, which is what Send wants; Preview is the forgiving variant.
func (*Renderer) RenderVersion ¶
func (r *Renderer) RenderVersion(version *Version, vars []Variable, data map[string]any) (*RenderedContent, error)
RenderVersion renders one version, active or not.
type Step ¶
type Step struct {
Try string `json:"try"`
Match Match `json:"match"`
Found bool `json:"found"`
VersionID string `json:"version_id,omitempty"`
}
Step is one lookup Resolve made: the locale it tried, which rule that was, and whether an active version answered.
type Store ¶
type Store interface {
// Template CRUD
CreateTemplate(ctx context.Context, t *Template) error
GetTemplate(ctx context.Context, templateID id.TemplateID) (*Template, error)
GetTemplateBySlug(ctx context.Context, appID string, slug string, channel string) (*Template, error)
UpdateTemplate(ctx context.Context, t *Template) error
DeleteTemplate(ctx context.Context, templateID id.TemplateID) error
ListTemplates(ctx context.Context, appID string) ([]*Template, error)
ListTemplatesByChannel(ctx context.Context, appID string, channel string) ([]*Template, error)
// Version CRUD
CreateVersion(ctx context.Context, v *Version) error
GetVersion(ctx context.Context, versionID id.TemplateVersionID) (*Version, error)
UpdateVersion(ctx context.Context, v *Version) error
DeleteVersion(ctx context.Context, versionID id.TemplateVersionID) error
ListVersions(ctx context.Context, templateID id.TemplateID) ([]*Version, error)
}
Store defines persistence operations for templates and their versions.
type Template ¶
type Template struct {
ID id.TemplateID `json:"id"`
AppID string `json:"app_id"`
Slug string `json:"slug"`
Name string `json:"name"`
Channel string `json:"channel"`
Category string `json:"category"`
Variables []Variable `json:"variables,omitempty"`
Versions []Version `json:"versions,omitempty"`
IsSystem bool `json:"is_system"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Template represents a notification template with locale-specific versions.
func DefaultTemplates ¶
DefaultTemplates returns the default notification templates to seed per app.
type Variable ¶
type Variable struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required"`
Default string `json:"default,omitempty"`
Description string `json:"description,omitempty"`
}
Variable describes an expected template variable.
type Version ¶
type Version struct {
ID id.TemplateVersionID `json:"id"`
TemplateID id.TemplateID `json:"template_id"`
Locale string `json:"locale"`
Subject string `json:"subject,omitempty"`
HTML string `json:"html,omitempty"`
Text string `json:"text,omitempty"`
Title string `json:"title,omitempty"`
Active bool `json:"active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Version represents a locale-specific content version of a template.