Documentation
¶
Overview ¶
Package admin serves the CMS admin area: login, dashboard, and user management, with content, media, and settings arriving in later phases. All UI assets are embedded; the package has no external runtime files.
Index ¶
- Constants
- func CSRFToken(r *http.Request) string
- func New(d Deps) http.Handler
- func RenderPage(w http.ResponseWriter, r *http.Request, title string, body template.HTML)
- func SectionPath(r *http.Request) string
- func SetFlash(r *http.Request, msg string)
- func UserFrom(r *http.Request) *auth.User
- func ValidateSections(sections []Section) error
- type Deps
- type Section
Constants ¶
const DefaultPerPage = 25
DefaultPerPage is how many rows a paginated admin list shows when Deps does not say. An editor's table is a working list rather than a page of a site, so it holds rather more than a public listing does.
const SectionPathPrefix = "/x"
SectionPathPrefix is the URL segment custom sections are mounted under, between the admin path and the section's own path: a section with Path "reports" serves {AdminPath}/x/reports. The namespace keeps host sections from ever colliding with built-in admin routes, present or future.
Variables ¶
This section is empty.
Functions ¶
func CSRFToken ¶
CSRFToken returns the session's CSRF token for a request served by a custom admin section. Forms that POST back to the section must send it in a hidden csrf_token field (or an X-CSRF-Token header); the admin middleware rejects unsafe requests without it.
func New ¶
New returns the admin http.Handler. The host mounts it under Deps.AdminPath with the prefix stripped.
func RenderPage ¶
RenderPage writes a 200 response wrapping body in the standard admin chrome (top bar, navigation, flash messages, admin stylesheet). Body is trusted host HTML, inserted unescaped. For any other status code or a fully custom look, write the response directly instead.
The admin serves a strict Content-Security-Policy with no unsafe-inline, so inline <script> and <style> in body are blocked by browsers; serve scripts and stylesheets as files from the section's own handler.
func SectionPath ¶
SectionPath returns the browser-facing base URL of the custom admin section serving this request, with a trailing slash — e.g. "/admin/x/reports/". Section handlers see mount-stripped paths, so a redirect after a POST must target this absolute URL, not a relative one:
http.Redirect(w, r, admin.SectionPath(r), http.StatusSeeOther)
Append a segment for sub-routes: SectionPath(r) + "settings". Outside a section handler it returns "".
func SetFlash ¶
SetFlash queues a one-time message shown at the top of the next admin page the user loads — the usual post/redirect/get confirmation. It is a no-op outside a section handler.
func UserFrom ¶
UserFrom returns the logged-in CMS user for a request served by a custom admin section. Inside a section handler it is never nil — the admin middleware has already required a login. Outside one it is nil.
func ValidateSections ¶
ValidateSections checks host-registered sections for empty, malformed, or duplicate paths and nil handlers. cms.New calls it; it is exported for hosts that want to fail earlier.
Types ¶
type Deps ¶
type Deps struct {
Sessions *scs.SessionManager
Users *auth.Store
Content *content.Store
Renderer *render.Renderer // nil when the host has not configured templates
// RequestFuncs binds the host's template functions
// (Config.TemplateFuncs) to a request, for the page and post
// previews. Previews run the same page templates the public site
// does, so a function that reads the request's context has to be
// bound here too or it behaves subtly differently under preview than
// in front of a visitor. Nil when the host registered none.
RequestFuncs func(*http.Request) template.FuncMap
Media *media.Manager // nil when the host has not configured an object store
Snippets *snippets.Store
Captcha *captcha.Client // nil when login CAPTCHA is not configured
ConfigSnippets []snippets.Snippet // host-registered palette entries
SectionStyles *render.SectionStyles // curated section settings
Sections []Section // host-registered admin pages, already validated
Logger *slog.Logger
AdminPath string
DefaultLocale string
Locales []string // all configured locales, [0] = DefaultLocale
// PostTemplate is the template blog and news posts render with; the
// zero value disables the Blog & News admin.
PostTemplate render.PageTemplate
// RememberFor is how long a "Remember me" login persists. The zero
// value falls back to 30 days so a partially-populated Deps (tests,
// direct package use) behaves sensibly.
RememberFor time.Duration
// PerPage is how many rows a paginated admin list shows on one page.
// The zero value falls back to DefaultPerPage, like RememberFor.
PerPage int
// SiteBaseURL returns the site's absolute public base
// ("scheme://host", no trailing slash) for the given request, so the
// admin can offer links that work when pasted somewhere else. Nil
// leaves such links site-relative, which is fine for tests and direct
// package use.
SiteBaseURL func(*http.Request) string
// ContentChanged, when set, is called (without waiting) after any
// mutation that can change which CSS classes stored content uses:
// region/section saves, publish/discard, page create/delete, and
// snippet changes. The CMS uses it to rebuild the generated
// Tailwind stylesheet.
ContentChanged func()
}
Deps is everything the admin area needs from the rest of the CMS.
type Section ¶
type Section struct {
// Path is the URL segment the section is mounted under: the section
// root is served at {AdminPath}/x/{Path}/ (the bare URL without the
// trailing slash redirects there, so relative links inside the
// section resolve under it). One path segment of RFC 3986 unreserved
// characters (letters, digits, "-", ".", "_", "~").
Path string
// means no nav link; the section is still routable.
NavLabel string
// AdminOnly restricts the section to users with the admin role.
// Editors receive 403 and don't see the nav link.
AdminOnly bool
// Handler serves the section's requests. The mount prefix is
// stripped: it sees "/" at the section root and may serve its own
// sub-routes and static assets beneath it. Requests only reach the
// handler with a logged-in user, and unsafe methods (POST, PUT, ...)
// have already passed CSRF validation — forms need only include
// CSRFToken(r) as the csrf_token field.
Handler http.Handler
}
Section is one host-registered admin extension: an http.Handler mounted inside the admin's middleware chain (session, CSRF validation, security headers, and login requirement), with an optional link in the admin's top navigation bar.