content

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package content defines the content object at the center of the CMS.

Index

Constants

View Source
const MaxDepth = 10

MaxDepth bounds how many levels of content nest under one another.

View Source
const PageWord = "page"

PageWord is the segment a numbered listing hides behind.

View Source
const TypePost = "post"

TypePost is the key of the built-in post type.

Variables

View Source
var ErrConflict = errors.New("content: conflicting update")

ErrConflict reports that the content item changed after the update was prepared.

View Source
var ErrCycle = errors.New("content: the item cannot nest inside itself")

ErrCycle reports that content would nest inside itself.

View Source
var ErrDefaultRequired = errors.New("content: the default type must stay")

ErrDefaultRequired reports that the default content type may not be deactivated or removed.

View Source
var ErrHoldsChildren = errors.New("content: the item still holds children")

ErrHoldsChildren reports that content still holds content nested under it.

View Source
var ErrInvalidAuthor = errors.New("content: invalid author")

ErrInvalidAuthor reports that a content item carries no author.

View Source
var ErrInvalidKey = errors.New("content: invalid type key")

ErrInvalidKey reports that a type key is not a lowercase word.

View Source
var ErrInvalidLabel = errors.New("content: invalid type label")

ErrInvalidLabel reports that a type carries no label.

View Source
var ErrInvalidOrder = errors.New("content: invalid order")

ErrInvalidOrder reports that a sort direction is not one the CMS sorts in.

View Source
var ErrInvalidOrderBy = errors.New("content: invalid orderby")

ErrInvalidOrderBy reports that a sort column is not one the CMS sorts by.

View Source
var ErrInvalidPageKind = errors.New("content: invalid page kind")

ErrInvalidPageKind reports that a page kind is not one the CMS renders.

View Source
var ErrInvalidRevisionCap = errors.New("content: invalid revision cap")

ErrInvalidRevisionCap reports that a revision cap is not a number of rows.

View Source
var ErrInvalidRouteWord = errors.New("content: invalid route word")

ErrInvalidRouteWord reports that a route word is not a lowercase word.

View Source
var ErrInvalidStatus = errors.New("content: invalid status")

ErrInvalidStatus reports that a status value is not one the CMS stores.

View Source
var ErrInvalidTransition = errors.New("content: invalid status transition")

ErrInvalidTransition reports that a status change is not allowed.

View Source
var ErrInvalidType = errors.New("content: invalid type")

ErrInvalidType reports that a content type is not registered.

View Source
var ErrNotFound = errors.New("content: not found")

ErrNotFound reports that no content item exists for the requested ID.

View Source
var ErrNotHierarchical = errors.New("content: the type does not nest")

ErrNotHierarchical reports that a content type does not nest.

View Source
var ErrPageKindUnavailable = errors.New("content: archive pages wait for relation fields")

ErrPageKindUnavailable reports that a page kind waits for relation fields.

View Source
var ErrParentTrashed = errors.New("content: the parent is in the trash")

ErrParentTrashed reports that a parent is on its way out of the site.

View Source
var ErrParentType = errors.New("content: the parent holds another kind of content")

ErrParentType reports that a parent holds another kind of content.

View Source
var ErrReservedAddress = errors.New("content: the address is reserved")

ErrReservedAddress reports that an address names a place the CMS keeps.

View Source
var ErrRevisionNotFound = errors.New("content: revision not found")

ErrRevisionNotFound reports that no revision exists for the requested ID.

View Source
var ErrRootTaken = errors.New("content: another type holds the root")

ErrRootTaken reports that another content type already lives at the root.

View Source
var ErrRouteWordReserved = errors.New("content: route word reserved")

ErrRouteWordReserved reports that the route word names a place the CMS keeps.

View Source
var ErrRouteWordTaken = errors.New("content: route word taken")

ErrRouteWordTaken reports that another content type answers under the route word.

View Source
var ErrSlugTaken = errors.New("content: slug taken")

ErrSlugTaken reports that a content type already holds the requested slug.

View Source
var ErrTooDeep = errors.New("content: the nesting limit is reached")

ErrTooDeep reports that content nests beyond the limit.

View Source
var ErrTypeInUse = errors.New("content: type still holds content")

ErrTypeInUse reports that the content type still holds content.

View Source
var ErrTypeInactive = errors.New("content: type is not active")

ErrTypeInactive reports that the content type is not active.

View Source
var ErrTypeNotFound = errors.New("content: type not found")

ErrTypeNotFound reports that no content type carries the requested key.

View Source
var ErrTypeTaken = errors.New("content: type key taken")

ErrTypeTaken reports that a content type already carries the requested key.

View Source
var ReservedRouteWords = []string{"admin", "api", "gophenberg", "_gophenberg", "media"}

ReservedRouteWords are the first address segments the CMS keeps for itself.

Functions

func AddressPrefix

func AddressPrefix(path, slug string) string

AddressPrefix returns the address an item's slug hangs from.

func AddressUnder

func AddressUnder(prefix, slug string) string

AddressUnder returns the address of a child carrying slug beneath prefix.

func FirstSegment

func FirstSegment(path string) string

FirstSegment returns the first segment of an address.

func ReservedRoot

func ReservedRoot(segment string) bool

ReservedRoot reports whether the segment names a place the CMS keeps for itself.

func Slugify

func Slugify(title string) string

Slugify returns title as a URL slug, or [untitledSlug] when it holds no slug characters.

Types

type Address

type Address struct {
	Kind Kind
	Type Type
	Item Content
	Page int
}

Address is what a public address holds.

type AddressReader

type AddressReader interface {
	PublishedByPath(ctx context.Context, path string) (Content, error)
}

AddressReader reads the published content an address holds.

type Content

type Content struct {
	ID          uuid.UUID
	Type        string
	ParentID    *uuid.UUID
	Path        string
	Slug        string
	Title       string
	Content     string
	Excerpt     string
	Status      Status
	AuthorID    uuid.UUID
	PublishedAt *time.Time
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

Content is a content item holding Gutenberg-serialized block HTML.

func New

func New(t Type, parent *Content, title string, authorID uuid.UUID) (Content, error)

New returns a draft Content of the given type under parent, slugged after its title.

func Reparent

func Reparent(t Type, c Content, parent *Content, height int) (Content, error)

Reparent returns the item and the height it carries nested under parent, or the reason they may not sit there.

func (Content) Place

func (c Content) Place(prefix, slug string) Content

Place returns the item carrying slug at the address beneath prefix.

func (Content) Rename

func (c Content) Rename(slug string) (Content, error)

Rename returns the item carrying slug where it already answers, or the reason it may not.

func (*Content) Restore

func (c *Content) Restore() error

Restore returns a trashed content item to draft, or reports ErrInvalidTransition.

func (*Content) Transition

func (c *Content) Transition(to Status) error

Transition moves the content item to the given status, stamping PublishedAt on the first publication and returning ErrInvalidTransition when disallowed.

type Filter

type Filter struct {
	Type    string
	Status  Status
	Search  string
	OrderBy OrderBy
	Order   Order
	Page    int
	PerPage int
}

Filter narrows a content listing.

type Kind

type Kind string

Kind names what an address holds.

const (
	KindItem    Kind = "item"
	KindArchive Kind = "archive"
)

The kinds of thing a public address answers with.

type Order

type Order string

Order names a sort direction.

const (
	OrderAsc  Order = "asc"
	OrderDesc Order = "desc"
)

The directions a listing can be sorted in.

func ParseOrder

func ParseOrder(raw string) (Order, error)

ParseOrder returns the direction named by raw, or ErrInvalidOrder.

type OrderBy

type OrderBy string

OrderBy names a column a listing can be sorted by.

const (
	OrderByDate  OrderBy = "date"
	OrderByTitle OrderBy = "title"
)

The columns a listing can be sorted by.

func ParseOrderBy

func ParseOrderBy(raw string) (OrderBy, error)

ParseOrderBy returns the column named by raw, or ErrInvalidOrderBy.

type PageKind

type PageKind string

PageKind is what the public page of one content item renders.

const (
	PageKindSingle  PageKind = "single"
	PageKindArchive PageKind = "archive"
)

The page kinds a content type declares. Archive waits for relation fields.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry answers which content types the CMS holds, caching what it reads.

func NewRegistry

func NewRegistry(store TypeStore) *Registry

NewRegistry returns a Registry reading through store.

func (*Registry) Active

func (r *Registry) Active(ctx context.Context, key string) (Type, error)

Active returns the type carrying the key when it is active, or the reason it serves nothing.

func (*Registry) All

func (r *Registry) All(ctx context.Context) ([]Type, error)

All returns every registered type, active or not, in registration order.

func (*Registry) ByKey

func (r *Registry) ByKey(ctx context.Context, key string) (Type, error)

ByKey returns the type carrying the key, or ErrTypeNotFound.

func (*Registry) ByRouteWord

func (r *Registry) ByRouteWord(ctx context.Context, word string) (Type, error)

ByRouteWord returns the active type answering under the word, or ErrTypeNotFound.

func (*Registry) Create

func (r *Registry) Create(ctx context.Context, t Type) (Type, error)

Create registers the type, or reports why it may not join the registry.

func (*Registry) Default

func (r *Registry) Default(ctx context.Context) (Type, error)

Default returns the type living at the root, or ErrTypeNotFound.

func (*Registry) Delete

func (r *Registry) Delete(ctx context.Context, key string) error

Delete removes the type, or reports why the registry keeps it.

func (*Registry) Update

func (r *Registry) Update(ctx context.Context, t Type) (Type, error)

Update stores the edited type, or reports why the registry keeps it as it stands.

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver answers what a public address holds.

func NewResolver

func NewResolver(store AddressReader, registry TypeReader) *Resolver

NewResolver returns a Resolver reading content through store and types through registry.

func (*Resolver) Resolve

func (r *Resolver) Resolve(ctx context.Context, raw string) (Address, error)

Resolve returns what the address holds, or ErrNotFound.

type Revision

type Revision struct {
	ID        uuid.UUID
	ContentID uuid.UUID
	Kind      RevisionKind
	AuthorID  uuid.UUID
	Title     string
	Content   string
	Excerpt   string
	CreatedAt time.Time
}

Revision is a snapshot of a content item's editable content.

func NewRevision

func NewRevision(c Content, kind RevisionKind, authorID uuid.UUID) (Revision, error)

NewRevision returns a snapshot of the item's editable content, credited to the given author.

type RevisionKind

type RevisionKind string

RevisionKind distinguishes an update snapshot from a per-author autosave.

const (
	RevisionKindRevision RevisionKind = "revision"
	RevisionKindAutosave RevisionKind = "autosave"
)

The kinds of revision a content item carries.

type Status

type Status string

Status is the publication state of a content item.

const (
	StatusDraft     Status = "draft"
	StatusPending   Status = "pending"
	StatusPrivate   Status = "private"
	StatusScheduled Status = "scheduled"
	StatusPublished Status = "published"
	StatusTrash     Status = "trash"
)

The statuses a content item may hold. Scheduled is stored but unreachable until a publish worker exists.

func ParseStatus

func ParseStatus(value string) (Status, error)

ParseStatus returns the Status named by value, or ErrInvalidStatus.

type Store

type Store interface {
	Create(ctx context.Context, c Content) (Content, error)
	ByID(ctx context.Context, id uuid.UUID) (Content, error)
	PublishedByPath(ctx context.Context, path string) (Content, error)
	Children(ctx context.Context, id uuid.UUID) (int, error)
	Depth(ctx context.Context, id uuid.UUID) (int, error)
	List(ctx context.Context, f Filter) ([]Content, int, error)
	Update(
		ctx context.Context, c Content, expectedUpdatedAt time.Time, snapshot *Revision, revisionCap int,
	) (Content, error)
	Trash(ctx context.Context, id uuid.UUID, updatedAt time.Time) (Content, error)
	Restore(ctx context.Context, id uuid.UUID, updatedAt time.Time) (Content, error)
	Delete(ctx context.Context, id uuid.UUID) error
	Counts(ctx context.Context, contentType string) (map[Status]int, error)
	Revisions(ctx context.Context, contentID uuid.UUID) ([]Revision, error)
	RevisionByID(ctx context.Context, contentID, revisionID uuid.UUID) (Revision, error)
	DeleteRevision(ctx context.Context, contentID, revisionID uuid.UUID) error
	SaveAutosave(ctx context.Context, autosave Revision) (Revision, error)
	Autosave(ctx context.Context, contentID, authorID uuid.UUID) (Revision, error)
	DeleteAutosave(ctx context.Context, contentID, authorID uuid.UUID) error
}

Store persists content items and their revisions.

type Type

type Type struct {
	Key           string
	SingularLabel string
	PluralLabel   string
	RouteWord     string
	Hierarchical  bool
	Revisions     bool
	RevisionCap   int
	PageKind      PageKind
	Default       bool
	Active        bool
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

Type describes a kind of content the CMS stores.

func NewType

func NewType(key, singular, plural, routeWord string) (Type, error)

NewType returns a content type ready to store, or the reason it is not one.

func (Type) Validate

func (t Type) Validate() error

Validate reports whether the type may be stored.

type TypeReader

type TypeReader interface {
	ByRouteWord(ctx context.Context, word string) (Type, error)
}

TypeReader answers which type answers under a route word.

type TypeStore

type TypeStore interface {
	List(ctx context.Context) ([]Type, error)
	ByKey(ctx context.Context, key string) (Type, error)
	Create(ctx context.Context, t Type) (Type, error)
	Update(ctx context.Context, t Type) (Type, error)
	Delete(ctx context.Context, key string) error
}

TypeStore persists the content type registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL