Documentation
¶
Overview ¶
Package catalog is ContentKit's own content: content items (a gallery, a movie, a creator or blog post), their per-language text, creators, versions with their text and segments, the state machine (draft, published, scheduled, deleted), the listing projection (content_facets), the one visibility rule every read applies, the retained event log and the catalog totals. Kinds are configuration (package kinds); nothing here names a host's nouns.
Index ¶
- Constants
- type AuthError
- type BodyImageInput
- type Content
- type ContentInput
- type ContentPatch
- type Cover
- type Creator
- type CreatorsInput
- type Decision
- type EntitySummary
- type Event
- type EventPage
- type EventQuery
- type EventRecord
- type ImportContent
- type ImportVersion
- type InlineImage
- type LanguageTotal
- type ManageCount
- type ManageQuery
- type ManagementName
- type ManagementNames
- type ManagementSearchQuery
- type OrderInput
- type PublicationStatus
- type Publish
- type PublishInput
- type Reader
- type Sanitizer
- type Segment
- type SegmentInput
- type SegmentsInput
- type Standing
- type Total
- type Totals
- type TotalsQuery
- type Update
- type Version
- type VersionInput
- type VersionKey
- type VersionPut
- type VersionStatus
- type VersionText
- type ViewerOptions
- type ViewerState
Constants ¶
const DefaultDeletedRetention = 30 * 24 * time.Hour
DefaultDeletedRetention is how long deleted content keeps its media and can be restored before PurgeDeleted erases it.
const DefaultEventRetention = 90 * 24 * time.Hour
DefaultEventRetention is independent of readers' progress.
const (
EventAudienceReleased = "version.audience_released"
)
const (
EventContentCreated = "content.created"
)
const (
EventContentDeleted = "content.deleted"
)
const (
EventContentPublished = "content.published"
)
const (
EventContentPurged = "content.purged"
)
const (
EventContentRestored = "content.restored"
)
const (
EventContentScheduled = "content.scheduled"
)
const (
EventContentUnpublished = "content.unpublished"
)
const (
EventContentUpdated = "content.updated"
)
const (
EventPublicationCompleted = "version.publication_completed"
)
const (
EventVersionCreated = "version.created"
)
const (
EventVersionDeleted = "version.deleted"
)
const (
EventVersionPublished = "version.published"
)
const (
EventVersionPurged = "version.purged"
)
const (
EventVersionUpdated = "version.updated"
)
const ImageScheme = "contentkit:"
ImageScheme is the URL scheme of an inline image reference in a body.
const MaxManageIDs = 100
MaxManageIDs bounds ManageQuery.IDs.
const MaxVersionStatuses = 100
MaxVersionStatuses bounds VersionStatuses.
const Queue = "contentkit_catalog"
Queue is the legacy base name. Runtime workers use QueueFor(catalog).
const (
StateDeleted = "deleted"
)
const (
StateDraft = "draft"
)
const (
StatePublished = "published"
)
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthError ¶
type AuthError struct{ Err error }
AuthError is a permission check the auth could not answer: 401 when the credential ended, else 503. It never grants.
type BodyImageInput ¶ added in v0.87.0
BodyImageInput names a body image uploaded to one version (Upload.Body).
type Content ¶
type Content struct {
ID string `json:"id"`
Kind string `json:"kind"`
// Code and Path are its page: /{lang}/{route}/{code}/{slug}.
Code string `json:"code"`
Path string `json:"path"`
// Language is the localized text language. Title may instead come from the
// selected edition or OriginalTitle under the kind's title policy.
Language string `json:"language"`
Title string `json:"title"`
// OriginalTitle and OriginalLanguage project the selected version only.
OriginalTitle string `json:"original_title,omitempty"`
OriginalLanguage string `json:"original_language,omitempty"`
// Slug is Path's decorative tail in the page's language (entity and
// title, "/"-joined); Slugs is it per language. Links built from them
// equal Path.
Slug string `json:"slug,omitempty"`
Slugs map[string]string `json:"slugs,omitempty"`
Description string `json:"description,omitempty"`
// Body shows each inline image with its selected edition's signed URL;
// only editors and viewers Decision allows get it. Description is the
// teaser everyone reads.
Body string `json:"body,omitempty"`
// Decision is the viewer's access to the item: allowed when they open any
// of its versions, else its first version's paywall.
Decision Decision `json:"decision"`
// Images maps each resolved image name of Body to its URL: the body
// images of the edition the viewer opens (DefaultVersion among them).
Images map[string]string `json:"images,omitempty"`
// Cover is the cover of the edition the request's language opens by
// default (DefaultVersion): what cards and meta tags show.
Cover *Cover `json:"cover,omitempty"`
State string `json:"state"`
// Comments is open, closed or hidden.
Comments string `json:"comments"`
PublishAt *time.Time `json:"publish_at,omitempty"`
PublishedAt *time.Time `json:"published_at,omitempty"`
Live bool `json:"live"`
Access access.Rule `json:"access"`
Restrictions []string `json:"restrictions"`
Attributes map[string]any `json:"attributes"`
ChannelID string `json:"channel_id,omitempty"`
// Channel identifies the original's primary authoring channel while active.
Channel *channels.Card `json:"channel,omitempty"`
Creators []Creator `json:"creators"`
// Entities are shared/null-version memberships. Version-specific entities
// are carried by each Version.Entities, never merged across editions here.
Entities []EntitySummary `json:"entities"`
Versions []Version `json:"versions"`
// SelectedVersionID is the edition selected for this response: the direct
// version lookup's edition, or the default among the visible versions.
SelectedVersionID string `json:"selected_version_id,omitempty"`
// Viewer is the signed-in reader's standing with the item, to resume
// it; each version carries its own.
Viewer *ViewerState `json:"viewer,omitempty"`
// Editor: the viewer may edit it; the fields below are theirs.
Editor bool `json:"editor"`
Revision int64 `json:"revision"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
}
Content is a resolved reader response. Text and media fields are read-only projections of SelectedVersionID; the parent stores no text. It includes live versions (every version for editors), entities and attributes. A viewer who opens none of its versions gets what its kind's locked view shows (kinds.Locked), and of each locked version what that view shows.
type ContentInput ¶
type ContentInput struct {
Kind string `json:"kind"`
// Comments is open (the default when permitted), closed (existing ones
// show, new ones are refused) or hidden. A kind excluding open defaults to
// its first configured comment mode.
Comments string `json:"comments,omitempty"`
// Access defaults to public when permitted, otherwise the kind's first
// allowed level (and the first configured tier for tier access).
Access *access.Rule `json:"access,omitempty"`
Restrictions []string `json:"restrictions,omitempty"`
Attributes map[string]any `json:"attributes,omitempty"`
// ChannelID is the primary channel; its current editors govern the item.
// It never changes.
ChannelID string `json:"channel_id,omitempty"`
// Creators nil credits the creating person as its author.
Creators *[]Creator `json:"creators,omitempty"`
// Versions defines initial editions. Omission creates one empty edition.
// A kind with hidden versions accepts at most one initial edition.
Versions []VersionInput `json:"versions,omitempty"`
}
ContentInput creates a content item, a draft until published.
type ContentPatch ¶
type ContentPatch struct {
Comments *string `json:"comments,omitempty"`
Access *access.Rule `json:"access,omitempty"`
Restrictions *[]string `json:"restrictions,omitempty"`
Attributes map[string]any `json:"attributes,omitempty"` // replaces all
Creators *[]Creator `json:"creators,omitempty"`
// Revision, when set, refuses the edit (409) unless it is current.
Revision *int64 `json:"revision,omitempty"`
}
ContentPatch edits a content item; nil fields stay.
type Cover ¶
type Cover struct {
Image string `json:"image,omitempty"`
URL *string `json:"url,omitempty"`
Renditions []media.PublicRendition `json:"renditions,omitempty"`
}
Cover is a version's cover: Image is the cover upload its editors selected ("i-{uuid}"; empty shows its first, else its kind's default); URL is its widest public rendition.
type Creator ¶
type Creator struct {
UserID string `json:"user_id"`
Role string `json:"role,omitempty"`
Position int `json:"position"`
}
Creator is a person credited on a content item. Credits do not grant access or editing authority; those follow the authenticated author and channel roles.
type CreatorsInput ¶
type CreatorsInput struct {
Creators []Creator `json:"creators"`
}
CreatorsInput replaces the creators.
type Decision ¶
type Decision struct {
Allowed bool `json:"allowed"`
// Unknown: entitlements could not be read; denied, nothing offered.
Unknown bool `json:"unknown,omitempty"`
// Sell is the keys a paywall offers; Requires the key a buyer holds first.
Sell []string `json:"sell,omitempty"`
Requires string `json:"requires,omitempty"`
// Preview is what a locked viewer still reads; Releases describe additional audiences.
Preview *access.Preview `json:"preview,omitempty"`
Releases []access.Release `json:"releases,omitempty"`
}
Decision is a viewer's access verdict on a version.
type EntitySummary ¶ added in v0.117.0
type EntitySummary struct {
ID string `json:"id"`
Kind string `json:"kind"`
Slug string `json:"slug"`
Name string `json:"name"`
Code string `json:"code,omitempty"`
Path string `json:"path,omitempty"`
}
EntitySummary names one entity a content item belongs to; Code and Path are its page, as content's are, when its kind has one.
type Event ¶
type Event struct {
ChannelID string
Type string
// Kind is the content's kind, or an entity event's entity kind.
Kind string
ContentID string
VersionID string
// EntityID is an entity event's subject; MergedInto its survivor.
EntityID string
MergedInto string
OccurredAt time.Time
Release *access.Release
PublicationID string
ChapterIDs []string
Released *bool
}
Event is the catalog fact appended by a mutation. Readers receive EventRecord.
type EventPage ¶ added in v0.116.0
type EventPage struct {
Events []EventRecord `json:"events"`
NextCursor string `json:"next_cursor"`
HasMore bool `json:"has_more"`
RetentionSeconds int64 `json:"retention_seconds"`
}
EventPage always provides a continuation, including an empty stream.
type EventQuery ¶ added in v0.116.0
EventQuery reads one app's retained log. Callers own their continuation.
type EventRecord ¶ added in v0.116.0
type EventRecord struct {
ID string `json:"id"`
Version int `json:"version"`
Type string `json:"type"`
Kind string `json:"kind"`
ContentID string `json:"content_id"`
VersionID string `json:"version_id,omitempty"`
// EntityID is an entity event's subject; MergedInto its survivor.
EntityID string `json:"entity_id,omitempty"`
MergedInto string `json:"merged_into,omitempty"`
OccurredAt time.Time `json:"occurred_at"`
RecordedAt time.Time `json:"recorded_at"`
Source string `json:"source"`
Scope string `json:"scope"`
Data json.RawMessage `json:"data,omitempty"`
}
EventRecord is an immutable committed catalog fact. IDs are decimal strings so JSON clients do not lose bigint precision.
type ImportContent ¶
type ImportContent struct {
ID string
Kind string
State string
PublishAt *time.Time
PublishedAt *time.Time
DeletedAt *time.Time
// Comments is open (when empty), closed or hidden.
Comments string
Access *access.Rule
Restrictions []string
Attributes map[string]any
ChannelID string
Creators []Creator
Versions []ImportVersion
Code string
CreatedAt *time.Time
UpdatedAt *time.Time
}
ImportContent is a content item as the bulk import writes it: its id, state and times kept, trusted (not screened). Nil Creators, Text and a version's Text keep what is stored; given ones replace it. Chapters are authored through PutVersions after content and source media are imported.
type ImportVersion ¶
type ImportVersion struct {
ID string
// Code is the version code to keep; empty keeps the stored one or
// assigns one. A version never changes its code.
Code string
Languages []string
Traits []string
Label string
State string
PublishAt *time.Time
PublishedAt *time.Time
DeletedAt *time.Time
Access *access.Rule
Attributes map[string]any
Ordinal *int
// Cover selects one of the version's cover uploads (i-{uuid}).
Cover string
OriginalTitle *string
OriginalLanguage *string
Text map[string]VersionText
CreatedAt *time.Time
UpdatedAt *time.Time
}
ImportVersion is one version of an ImportContent, positioned as listed.
type InlineImage ¶
InlineImage is an inline image of a body: Ref goes where its URL would ("contentkit:i-{uuid}"); URL shows it to the editor now (null until it has a file to show).
type LanguageTotal ¶
LanguageTotal sizes one kind in one language, as Total does.
type ManageCount ¶ added in v0.104.0
type ManageCount struct {
Total int `json:"total"`
// Truncated makes Total a lower bound.
Truncated bool `json:"truncated,omitempty"`
}
ManageCount is how many items a manage listing selects.
type ManageQuery ¶
type ManageQuery struct {
Kind string
// State is draft, scheduled, published (live) or deleted; "" is every
// state but deleted.
State string
Channel string
// Text matches title, description or body, ignoring case.
Text string
// Code selects the item with this content code; with State "" it matches
// deleted items too, so editor links keep resolving.
Code string
// IDs selects these items (at most MaxManageIDs); with State "" it
// matches deleted items too, so member lists resolve every member.
IDs []string
// Access keeps items whose own rule has this level; Tier those whose rule
// names this configured tier (implying the tier level).
Access, Tier string
Limit, Offset int
}
ManageQuery selects content items to manage.
type ManagementName ¶ added in v0.104.0
type ManagementName struct{ ID, Kind, Title, Language string }
ManagementName is the current name of an item its caller may edit. No body, media, public-listing policy or audience billing check is needed to navigate.
type ManagementNames ¶ added in v0.104.0
type ManagementNames struct {
Contents []ManagementName
Entities []entities.EntityCard
}
type ManagementSearchQuery ¶ added in v0.104.0
type PublicationStatus ¶ added in v0.128.0
type PublicationStatus struct {
ID string `json:"id"`
State string `json:"state"`
ScheduledAt time.Time `json:"scheduled_at"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
Error string `json:"error,omitempty"`
}
PublicationStatus is the latest accepted edition publication operation. Its state describes work; Version.Live describes current reader availability.
type PublishInput ¶
PublishInput publishes now, or at PublishAt when it is in the future.
type Reader ¶
type Reader interface {
Read(ctx context.Context, ref contentref.ContentRef, actor access.Actor, o media.ReadOptions) (*media.ReadResult, error)
// NamedURLs signs an opened item's named images that have no public files.
NamedURLs(ctx context.Context, ref contentref.ContentRef, actor access.Actor, names []string) (map[string]string, error)
}
Reader reads an item as the media read API does.
type Sanitizer ¶
type Sanitizer = content.ContentProcessor
Sanitizer cleans rich text on write: content.ContentProcessor.
type Segment ¶
type Segment struct {
ID string `json:"id"`
Position int `json:"position"`
Title string `json:"title,omitempty"`
StartPage string `json:"start_page,omitempty"`
Start int `json:"start"`
End int `json:"end"`
ReleaseAt *time.Time `json:"release_at,omitempty"`
ReleasedAt *time.Time `json:"released_at,omitempty"`
Released bool `json:"released"`
}
Segment is a chapter of one version. StartPage names its first file in manifest order; the next chapter's marker or the end of the manifest ends it. ReleaseAt is intent. ReleasedAt is set only after durable publication.
type SegmentInput ¶ added in v0.106.0
type SegmentInput struct {
ID string `json:"id,omitempty"`
Position int `json:"position,omitempty"`
Title string `json:"title,omitempty"`
StartPage string `json:"start_page,omitempty"`
Start int `json:"-"` // rejected legacy Go input; never a wire field
End int `json:"-"` // rejected legacy Go input; never a wire field
ReleaseAt *time.Time `json:"release_at,omitempty"`
Released bool `json:"released,omitempty"` // ignored, retained for older clients
}
SegmentInput authors a chapter by its first virtual filename in the manifest. ID preserves the chapter across title, ordering and marker edits. Numeric range authoring is rejected; Start and End exist only on displayed chapters and the separate trusted import model.
type SegmentsInput ¶
type SegmentsInput struct {
Segments []SegmentInput `json:"segments"`
}
SegmentsInput replaces a version's segments.
type Standing ¶ added in v0.85.0
type Standing interface {
Standing(ctx context.Context, actor access.Actor, refs []contentref.ContentRef) ([]ViewerState, error)
}
Standing reads a signed-in person's standing with content items and versions, per ref in order: *discovery.Service.
type Total ¶
type Total struct {
Public int64 `json:"public"`
Tiers map[string]int64 `json:"tiers"`
Languages map[string]LanguageTotal `json:"languages"`
}
Total sizes one kind. Public counts what an anonymous visitor's listing shows and opens; Tiers[t] every eligible item a holder of t opens, members-listed ones included. An item counts once in the kind's total and once per language any of its eligible versions serves, never per version. The site's scope and the default content filters apply.
type TotalsQuery ¶
type TotalsQuery struct {
// Kinds are content kinds; empty means all of them.
Kinds []string
// Languages are the languages Total.Languages reports; empty means every
// language with a counted item. Kind totals ignore it.
Languages []string
// Domain is the stable domain name whose scope applies; empty selects
// main. The HTTP route takes it from the request's host.
Domain string
}
TotalsQuery selects the kinds and languages to total.
type Version ¶
type Version struct {
ID string `json:"id"`
// Code selects it on its content's page (?v=): unique within the content,
// fixed for the version's life.
Code string `json:"code"`
Position int `json:"position"`
Languages []string `json:"languages"`
Traits []string `json:"traits"`
Label string `json:"label,omitempty"`
// Resolved text is selected from this version only in the request language.
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Language string `json:"language,omitempty"`
Slug string `json:"slug,omitempty"`
Body string `json:"body,omitempty"`
Images map[string]string `json:"images,omitempty"`
OriginalTitle string `json:"original_title,omitempty"`
OriginalLanguage string `json:"original_language,omitempty"`
// State is the editors' to see.
State string `json:"state,omitempty"`
PublishAt *time.Time `json:"publish_at,omitempty"`
PublishedAt *time.Time `json:"published_at,omitempty"`
// Publication is editor-only durable work status. A pending update does
// not replace the edition's already released reader state.
Publication *PublicationStatus `json:"publication,omitempty"`
// Live reports a completed release under the current publication state.
Live bool `json:"live"`
// Access is the version's own rule. Noneditors do not receive this field.
Access *access.Rule `json:"access,omitempty"`
Attributes map[string]any `json:"attributes"`
// Entities are entities attached specifically to this version. Combine them
// with Content.Entities when presenting the selected version's credits.
Entities []EntitySummary `json:"entities"`
Pages *int `json:"pages,omitempty"`
DurationMS *int64 `json:"duration_ms,omitempty"`
Width *int `json:"width,omitempty"`
Height *int `json:"height,omitempty"`
HasAudio bool `json:"has_audio"`
Ordinal *int `json:"ordinal,omitempty"`
// Cover is absent when its kind's locked view hides it from the viewer.
Cover *Cover `json:"cover,omitempty"`
Segments []Segment `json:"segments"`
Decision Decision `json:"decision"`
// Text is every authored language of this edition, for editors.
Text map[string]VersionText `json:"text,omitempty"`
// Viewer is the signed-in reader's standing with the version.
Viewer *ViewerState `json:"viewer,omitempty"`
}
Version is what a viewer opens.
type VersionInput ¶
type VersionInput struct {
Languages []string `json:"languages,omitempty"`
Traits *[]string `json:"traits,omitempty"`
Label *string `json:"label,omitempty"`
// State is draft or published intent. A version becomes live only when its
// durable publication completes. A version created with its gallery
// defaults to published intent, one added later to draft.
State string `json:"state,omitempty"`
PublishAt *time.Time `json:"publish_at,omitempty"`
// Access is this edition's rule. ClearAccess copies the current gallery
// creation default once; subsequent gallery edits never change it.
Access *access.Rule `json:"access,omitempty"`
ClearAccess bool `json:"clear_access,omitempty"`
Attributes map[string]any `json:"attributes,omitempty"` // replaces all
Text map[string]VersionText `json:"text,omitempty"` // replaces all
Segments *[]SegmentInput `json:"segments,omitempty"` // replaces all
Ordinal *int `json:"ordinal,omitempty"`
// Cover selects one of the version's cover uploads by name (i-{uuid});
// "" returns to its first.
Cover *string `json:"cover,omitempty"`
OriginalTitle *string `json:"original_title,omitempty"`
OriginalLanguage *string `json:"original_language,omitempty"`
}
VersionInput creates or edits a version; nil fields stay (or default).
type VersionKey ¶
type VersionKey struct{ ContentID, VersionID string }
VersionKey names one version.
type VersionPut ¶
type VersionPut struct {
ContentID string
VersionID string
VersionInput
}
VersionPut creates (VersionID "") or edits a version.
type VersionStatus ¶ added in v0.135.0
type VersionStatus struct {
VersionID string `json:"version_id"`
ContentID string `json:"content_id"`
Kind string `json:"kind"`
Languages []string `json:"languages"`
// Deleted is the edition's or its content's deletion.
Deleted bool `json:"deleted"`
// Live is released and not deleted at the time of the read.
Live bool `json:"live"`
// LiveFrom is when its release completed, kept through deletion; absent
// before release.
LiveFrom *time.Time `json:"live_from,omitempty"`
}
VersionStatus is an edition's catalog state, for hosts that keep references to editions. A purged edition has none.
type VersionText ¶
type VersionText struct {
Title string `json:"title"`
Slug string `json:"slug,omitempty"`
Description string `json:"description,omitempty"`
Body string `json:"body,omitempty"`
SortKey string `json:"sort_key,omitempty"`
Aliases []string `json:"aliases,omitempty"`
}
VersionText is one edition's authored text in one language. Inline images resolve only against this edition's media; no sibling or parent fallback.
type ViewerOptions ¶
type ViewerOptions struct {
Actor access.Actor
// Host is the request's host; it picks the site (kinds.Config.DomainFor).
Host string
// Language, when set, lists only content with a live version serving it.
Language string
// Mode defaults to access.Lock.
Mode access.Mode
// EditorEntities are owner entities (channels) whose editors see their whole
// content in lists; the viewer's editorship of each is checked.
EditorEntities []string
// Requested are entities a list requires (an entity's page): the viewer's
// content filters do not hide them, so the page shows what the entity's
// count counts.
Requested []string
}
ViewerOptions describes one request's reader.
type ViewerState ¶ added in v0.85.0
type ViewerState struct {
Favorited bool `json:"favorited"`
// Reaction is their like (1) or dislike (-1) of the item; absent for neither.
Reaction int `json:"reaction,omitempty"`
// Seen, Completed, Progress, ProgressMax and Resume (the client's own
// pointer, such as a page) come from the signal plane. Progress counts
// whole pages for a reader and seconds for a player.
Seen bool `json:"seen"`
Completed bool `json:"completed"`
Progress uint32 `json:"progress"`
ProgressMax uint32 `json:"progress_max"`
Resume string `json:"resume,omitempty"`
LastReadAt *time.Time `json:"last_read_at,omitempty"`
}
ViewerState is a signed-in reader's own standing with a content item or version: their favorite and, with a signal plane, where they are in it.