Documentation
¶
Overview ¶
Package site is the public front controller: it maps public URLs to content, terms and listings and renders them through the active theme (theme.Service). It also serves theme assets, sitemap.xml/robots.txt (via seo.Service) and the contact form.
Index ¶
Constants ¶
const ( SettingFormsNotify = "forms.notify" // bool, default true: mail each stored submission SettingFormsRecipients = "forms.recipients" // "a@x.com, b@y.com"; empty: contact.email, else the first admin SettingAttachments = "contact.attachments" // bool, default false: accept one file per submission SettingAttachmentMaxMB = "contact.attachment_max_mb" // 1–20, default 5 )
Form settings. The contact.* flags are public (themes read them with {{setting}} to show the file input); forms.* stay private because the recipient list holds staff addresses.
const DefaultPolicyDirectory = "/var/lib/gorun-site-policies"
DefaultPolicyDirectory is the root-owned directory GORUN_SITE_POLICY files must live in, unless a build sets another one with SetPolicyDirectory.
const ( // HookFormSubmitted is emitted (async) for every accepted form // submission; the site module itself subscribes (deliverForm) and mails // it to contact.email through the mailer service. HookFormSubmitted = "site.form.submitted" )
const KindFormResult = "form-result"
KindFormResult is the theme kind rendered after a form submission.
const PermIntakeReview = "intake.review"
const ( // PermSubmissions guards System → Form submissions (an existing // permission: no new grant needed). PermSubmissions = "settings.manage" )
const SettingAvailability = "site.availability"
const SettingContactEmail = "contact.email"
SettingContactEmail is the recipient of contact form messages; when it is unset or invalid the first active admin's email is used.
const SettingMaintenance = "site.maintenance"
SettingMaintenance (bool) puts the public site in maintenance: every public page answers 503 with a short notice, while the admin, the API, MCP, /healthz, the sitemap, robots.txt, media and theme assets keep working.
Variables ¶
var ErrFormSetting = errors.New("invalid form setting")
ErrFormSetting is wrapped by every ValidateFormSetting rejection.
var FormSettingKeys = []string{SettingFormsNotify, SettingFormsRecipients, SettingAttachments, SettingAttachmentMaxMB}
FormSettingKeys lists the keys ValidateFormSetting accepts.
Functions ¶
func SetPolicyDirectory ¶
func SetPolicyDirectory(dir string)
SetPolicyDirectory sets the trusted policy directory for this process. It is a build-time choice (call it from main before Boot), not configuration: the directory is a trust root, so it never comes from the environment. An empty or relative dir is ignored.
func ValidateFormSetting ¶
ValidateFormSetting validates one form setting given as text (the admin form, `gorun settings set`) and returns the value to store: a bool for the flags, an int for the size and a normalised list for recipients.
Types ¶
type Availability ¶
type FormDefinition ¶ added in v0.19.0
type FormDefinition struct {
ID string `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
Source string `json:"source"`
PageID string `json:"page_id"`
// SubmitLabel and Success are a builder form's button label and success
// message ("" for captured forms).
SubmitLabel string `json:"submit_label"`
Success string `json:"success"`
Fields []FormField `json:"fields"`
Open bool `json:"open"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
FormDefinition is a forms row. PageID is the builder page that declares it ("" for captured forms).
type FormField ¶ added in v0.19.0
type FormField struct {
Name string `json:"name"`
Label string `json:"label"`
Type string `json:"type"`
Required bool `json:"required"`
Help string `json:"help,omitempty"`
Choices []string `json:"choices,omitempty"`
State string `json:"state"` // pinned | discovered
Hidden bool `json:"hidden,omitempty"`
// AdminLabel is the admin's rename ("" shows Label); AdminPos the
// admin's column position (0 = not placed: after placed fields, in
// schema order).
AdminLabel string `json:"admin_label,omitempty"`
AdminPos int `json:"admin_pos,omitempty"`
}
FormField is one field of a form's schema, in schema order (the builder's, or first-seen for a captured form). Label, order, type, required and choices are the published schema the visitor form renders; Hidden, AdminLabel and AdminPos are admin presentation only.
func (FormField) DisplayLabel ¶ added in v0.19.0
DisplayLabel is the label the admin tables and CSV headers show.
type FormState ¶
type FormState struct {
OK bool
Errors map[string]string // field → i18n key
Values map[string]string
Back string
// Message is a builder form's own success text (plain text, escaped by
// the template), shown instead of the generic one when set; Form is
// that form's slug, which the flash fallback carries.
Message string
Form string
}
FormState is passed to form-result.html as .Extra.form.
type FormSubmission ¶
type FormSubmission struct {
ID string `json:"id"`
Form string `json:"form"`
Fields map[string]string `json:"fields,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Message string `json:"message"`
Page string `json:"page"`
IP string `json:"ip"`
SubmittedAt string `json:"submitted_at"`
AttachmentName string `json:"attachment_name,omitempty"`
AttachmentType string `json:"attachment_type,omitempty"`
AttachmentSize int64 `json:"attachment_size,omitempty"`
}
FormSubmission is the HookFormSubmitted payload. It carries attachment metadata only; delivery reads the file from <data>/form-uploads/<id>. For the contact form ID is the form_submissions row and Name, Email and Message are set; for any other form (Form is its slug) ID is the form_entries row and Fields holds the stored values.
type Module ¶
type Module struct{}
Module is the site kernel.Module. It registers after redirects, so the redirects middleware (Router.Public.Use) already wraps these routes.
func (*Module) Migrations ¶
Migrations implements kernel.Module (form_submissions).
func (*Module) Register ¶
Register mounts the public routes. Specific routes come first; GET /* dispatches everything else (archives, singles, terms, pages, 404). Routes rendering forms pass through auth.CSRFMiddleware (on these routes only, never Public.Use: other modules' public POSTs have their own rules); POST /forms/contact first passes contactGuard, POST /forms/{slug} formGuard.
type Submission ¶
type Submission struct {
FormSubmission
Source formSource
Status, Delivery, DeliveryError string
}
Submission is one stored form_submissions row: the submission as posted (SubmittedAt is the row's created_at) plus its inbox state.
func (Submission) SizeText ¶
func (s Submission) SizeText() string
SizeText is the attachment size for display.
Source Files
¶
- alternates.go
- availability.go
- availability_admin.go
- availability_cookie.go
- availability_http.go
- comments.go
- errors.go
- form_sources.go
- forms.go
- forms_admin.go
- forms_any.go
- forms_mail.go
- forms_render.go
- formsettings.go
- handlers.go
- identity_assets.go
- intake_admin.go
- intake_public.go
- intake_store.go
- maintenance.go
- module.go
- page_access.go
- page_access_admin.go
- router.go
- static.go
- submissions.go
- submissions_admin.go
- uploads.go