Content management with publishing workflow and block-based content
| Tier | content |
| Role | unclassified (baselined) |
| Path | crates/content/cms |
| Edition | 2021 |
| Targets | content_cms |
| Public items | 225 across 10 modules |
| Tests | 160 |
What it is for
# content-cms
Content management library crates with publishing workflow and block-based content.
Core Concepts
- Content Pages: Support both regular pages and blog posts
- Publishing Workflow: Draft → Published → Archived with immutable snapshots
- Block-Based Content: Extensible block system for flexible layouts
- Access Control: Public, Authenticated, Role-based, and Entitlement levels
- SEO Support: Metadata, Open Graph, canonical URLs, robots directives
Example
use content_cms::{
ContentPage, ContentBlock, BlogCategory, Redirect,
PageType, PageStatus, AccessLevel,
snapshot::publish_page,
};
use uuid::Uuid;
// Create a blog post
let mut post = ContentPage::builder()
.slug("hello-world")
.title("Hello World")
.post()
.excerpt("My first blog post")
.seo_description("An introduction to our blog")
.build();
// Add content blocks
let blocks = vec
ContentBlock::builder()
.page(post.id)
.hero()
.data(serde_json::json!({
"title": "Welcome to My Blog",
"background_url": "/images/hero.jpg"
}))
.sequence(0)
.build(),
ContentBlock::builder()
.page(post.id)
.rich_text()
.data(serde_json::json!({
"content": "<p>This is my first post...</p>"
}))
.sequence(1)
.build(),
;
// Publish the post
let publisher_id = Uuid::new_v4();
let snapshot = publish_page(&mut post, &blocks, publisher_id);
assert!(post.is_published());
assert!(snapshot.verify_checksum());
Capabilities
ContentBlock:ContentBlock
ContentBlock model for block-based page content.
| Item |
|---|
pub struct ContentBlock |
ContentBlock:builder
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn builder() -> ContentBlockBuilder |
ContentBlock:created
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn created_at(& self) -> DateTime <Utc> |
ContentBlock:deleted
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn deleted_at(& self) -> Option <DateTime <Utc>> |
ContentBlock:get
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn get_string(& self, key : & str) -> Option <& str> |
ContentBlock :: fn get_i64(& self, key : & str) -> Option <i64> |
ContentBlock :: fn get_bool(& self, key : & str) -> Option <bool> |
ContentBlock:id
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn id(& self) -> Uuid |
ContentBlock:is
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn is_for_page(& self, page_id : Uuid) -> bool |
ContentBlock :: fn is_type(& self, block_type : & str) -> bool |
ContentBlock :: fn is_active(& self) -> bool |
ContentBlock :: fn is_inactive(& self) -> bool |
ContentBlock:restore
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn restore(& mut self) |
ContentBlock:soft
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn soft_delete(& mut self) |
ContentBlock:updated
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlock :: fn updated_at(& self) -> DateTime <Utc> |
ContentBlockBuilder:ContentBlockBuilder
ContentBlock model for block-based page content.
| Item |
|---|
pub struct ContentBlockBuilder |
ContentBlockBuilder:active
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn active(mut self, is_active : bool) -> Self |
ContentBlockBuilder:block
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn block_type(mut self, block_type : impl Into <String>) -> Self |
ContentBlockBuilder:build
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn build(self) -> ContentBlock |
ContentBlockBuilder:cta
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn cta(self) -> Self |
ContentBlockBuilder:data
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn data(mut self, data : JsonValue) -> Self |
ContentBlockBuilder:divider
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn divider(self) -> Self |
ContentBlockBuilder:embed
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn embed(self) -> Self |
ContentBlockBuilder:heading
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn heading(self) -> Self |
ContentBlockBuilder:hero
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn hero(self) -> Self |
ContentBlockBuilder:image
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn image(self) -> Self |
ContentBlockBuilder :: fn image_gallery(self) -> Self |
ContentBlockBuilder:inactive
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn inactive(mut self) -> Self |
ContentBlockBuilder:new
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn new() -> Self |
ContentBlockBuilder:page
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn page(mut self, page_id : Uuid) -> Self |
ContentBlockBuilder:rich
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn rich_text(self) -> Self |
ContentBlockBuilder:sequence
ContentBlock model for block-based page content.
| Item |
|---|
ContentBlockBuilder :: fn sequence(mut self, sequence : u32) -> Self |
block::block_types (other)
_No module-level documentation is present in the source._
| Item |
|---|
pub const RICH_TEXT: & str |
pub const HEADING: & str |
pub const IMAGE: & str |
pub const IMAGE_GALLERY: & str |
pub const HERO: & str |
pub const CTA: & str |
pub const EMBED: & str |
pub const DIVIDER: & str |
pub const ALL: & & str |
fn is_builtin(block_type : & str) -> bool |
BlogCategory
BlogCategory model for organizing blog posts.
| Item |
|---|
pub struct BlogCategory |
BlogCategory :: fn builder() -> BlogCategoryBuilder |
BlogCategory :: fn matches_slug(& self, slug : & str) -> bool |
BlogCategory :: fn slugify(name : & str) -> String |
BlogCategory :: fn id(& self) -> Uuid |
BlogCategory :: fn created_at(& self) -> DateTime <Utc> |
BlogCategory :: fn updated_at(& self) -> DateTime <Utc> |
BlogCategory :: fn deleted_at(& self) -> Option <DateTime <Utc>> |
BlogCategory :: fn soft_delete(& mut self) |
BlogCategory :: fn restore(& mut self) |
BlogCategoryBuilder
BlogCategory model for organizing blog posts.
| Item |
|---|
pub struct BlogCategoryBuilder |
BlogCategoryBuilder :: fn new() -> Self |
BlogCategoryBuilder :: fn name(mut self, name : impl Into <String>) -> Self |
BlogCategoryBuilder :: fn slug(mut self, slug : impl Into <String>) -> Self |
BlogCategoryBuilder :: fn description(mut self, description : impl Into <String>) -> Self |
BlogCategoryBuilder :: fn color(mut self, color : impl Into <String>) -> Self |
BlogCategoryBuilder :: fn sort_order(mut self, order : i32) -> Self |
BlogCategoryBuilder :: fn build(self) -> BlogCategory |
AccessLevel
CMS enums for page type, status, and access control.
| Item |
|---|
pub enum AccessLevel |
AccessLevel :: fn as_str(& self) -> & 'static str |
AccessLevel :: fn requires_auth(& self) -> bool |
AccessLevel :: fn is_public(& self) -> bool |
AccessLevel :: fn is_role_based(& self) -> bool |
AccessLevel :: fn is_entitlement_based(& self) -> bool |
AccessLevel :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
AccessLevel :: fn from_str(s : & str) -> Result <Self, Self::Err> |
PageStatus
CMS enums for page type, status, and access control.
| Item |
|---|
pub enum PageStatus |
PageStatus :: fn as_str(& self) -> & 'static str |
PageStatus :: fn is_published(& self) -> bool |
PageStatus :: fn is_draft(& self) -> bool |
PageStatus :: fn is_archived(& self) -> bool |
PageStatus :: fn is_visible(& self) -> bool |
PageStatus :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
PageStatus :: fn from_str(s : & str) -> Result <Self, Self::Err> |
PageType
CMS enums for page type, status, and access control.
| Item |
|---|
pub enum PageType |
PageType :: fn as_str(& self) -> & 'static str |
PageType :: fn is_post(& self) -> bool |
PageType :: fn is_page(& self) -> bool |
PageType :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
PageType :: fn from_str(s : & str) -> Result <Self, Self::Err> |
CMSError:CMSError
CMS error types.
| Item |
|---|
pub enum CMSError |
CMSError:access
CMS error types.
| Item |
|---|
CMSError :: fn access_denied(slug : impl Into <String>, reason : impl Into <String>) -> Self |
CMSError:block
CMS error types.
| Item |
|---|
CMSError :: fn block_not_found(id : Uuid) -> Self |
CMSError :: fn block_validation_failed(block_type : impl Into <String>, message : impl Into <String>,) -> Self |
CMSError:cannot
CMS error types.
| Item |
|---|
CMSError :: fn cannot_publish(reason : impl Into <String>) -> Self |
CMSError:category
CMS error types.
| Item |
|---|
CMSError :: fn category_not_found(id : Uuid) -> Self |
CMSError :: fn category_not_found_by_slug(slug : impl Into <String>) -> Self |
CMSError:duplicate
CMS error types.
| Item |
|---|
CMSError :: fn duplicate_slug(slug : impl Into <String>) -> Self |
CMSError :: fn duplicate_redirect_path(path : impl Into <String>) -> Self |
CMSError:invalid
CMS error types.
| Item |
|---|
CMSError :: fn invalid_slug(slug : impl Into <String>) -> Self |
CMSError :: fn invalid_block_type(block_type : impl Into <String>) -> Self |
CMSError :: fn invalid_seo_field(field : impl Into <String>, message : impl Into <String>) -> Self |
CMSError:not
CMS error types.
| Item |
|---|
CMSError :: fn not_published(id : Uuid) -> Self |
CMSError:page
CMS error types.
| Item |
|---|
CMSError :: fn page_not_found(id : Uuid) -> Self |
CMSError :: fn page_not_found_by_slug(slug : impl Into <String>) -> Self |
CMSError:redirect
CMS error types.
| Item |
|---|
CMSError :: fn redirect_not_found(id : Uuid) -> Self |
CMSError :: fn redirect_not_found_by_path(path : impl Into <String>) -> Self |
CMSError:version
CMS error types.
| Item |
|---|
CMSError :: fn version_page_mismatch(version_id : Uuid, version_page_id : Uuid, page_id : Uuid) -> Self |
lifecycle (other)
Version-pair content lifecycle.
| Item |
|---|
fn save_draft(page : & mut ContentPage, draft_version : & PageVersion) -> Result <(), CMSError> |
fn publish_draft(page : & mut ContentPage, publish_version : & PageVersion, published_by : Uuid,) -> Result <(), CMSError> |
fn rollback(page : & mut ContentPage, target : & PageVersion, published_by : Uuid,) -> Result <(), CMSError> |
DraftState
Version-pair content lifecycle.
| Item |
|---|
pub enum DraftState |
DraftState :: fn as_str(& self) -> & 'static str |
DraftState :: fn has_unpublished_changes(& self) -> bool |
fn draft_state(page : & ContentPage) -> DraftState |
fn draft_state_from(published_version_id : Option <Uuid>, draft_version_id : Option <Uuid>,) -> DraftState |
RenderMode
Version-pair content lifecycle.
| Item |
|---|
pub enum RenderMode |
fn get_page_for_render(page : & ContentPage, published_version : Option <& PageVersion>, mode : RenderMode,) -> Result <ContentPage, CMSError> |
page (other)
ContentPage model for CMS pages and blog posts.
| Item |
|---|
fn depth_of_slug(slug : & str) -> usize |
ContentPage:ContentPage
ContentPage model for CMS pages and blog posts.
| Item |
|---|
pub struct ContentPage |
ContentPage:builder
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn builder() -> ContentPageBuilder |
ContentPage:can
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn can_access(& self, user_id : Option <Uuid>, user_roles : & String, is_staff : bool) -> bool |
ContentPage:created
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn created_at(& self) -> DateTime <Utc> |
ContentPage:deleted
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn deleted_at(& self) -> Option <DateTime <Utc>> |
ContentPage:depth
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn depth(& self) -> usize |
ContentPage:effective
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn effective_seo_title(& self) -> & str |
ContentPage:has
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn has_snapshot(& self) -> bool |
ContentPage:id
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn id(& self) -> Uuid |
ContentPage:is
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn is_post(& self) -> bool |
ContentPage :: fn is_page(& self) -> bool |
ContentPage :: fn is_published(& self) -> bool |
ContentPage :: fn is_draft(& self) -> bool |
ContentPage :: fn is_archived(& self) -> bool |
ContentPage :: fn is_public(& self) -> bool |
ContentPage:matches
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn matches_slug(& self, slug : & str) -> bool |
ContentPage:restore
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn restore(& mut self) |
ContentPage:soft
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn soft_delete(& mut self) |
ContentPage:updated
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPage :: fn updated_at(& self) -> DateTime <Utc> |
ContentPageBuilder:ContentPageBuilder
ContentPage model for CMS pages and blog posts.
| Item |
|---|
pub struct ContentPageBuilder |
ContentPageBuilder:access
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn access_level(mut self, level : AccessLevel) -> Self |
ContentPageBuilder:archived
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn archived(mut self) -> Self |
ContentPageBuilder:authenticated
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn authenticated(mut self) -> Self |
ContentPageBuilder:author
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn author(mut self, author_id : Uuid) -> Self |
ContentPageBuilder:build
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn build(self) -> ContentPage |
ContentPageBuilder:canonical
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn canonical_url(mut self, url : impl Into <String>) -> Self |
ContentPageBuilder:category
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn category(mut self, category_id : Uuid) -> Self |
ContentPageBuilder:draft
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn draft(mut self) -> Self |
ContentPageBuilder:entitlement
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn entitlement_access(mut self, entitlements : Vec <String>) -> Self |
ContentPageBuilder:excerpt
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn excerpt(mut self, excerpt : impl Into <String>) -> Self |
ContentPageBuilder:featured
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn featured_image_url(mut self, url : impl Into <String>) -> Self |
ContentPageBuilder:indexable
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn indexable(mut self, indexable : bool) -> Self |
ContentPageBuilder:metadata
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn metadata(mut self, metadata : JsonValue) -> Self |
ContentPageBuilder:new
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn new() -> Self |
ContentPageBuilder:og
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn og_image_url(mut self, url : impl Into <String>) -> Self |
ContentPageBuilder:page
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn page(mut self) -> Self |
ContentPageBuilder :: fn page_type(mut self, page_type : PageType) -> Self |
ContentPageBuilder:post
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn post(mut self) -> Self |
ContentPageBuilder:public
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn public(mut self) -> Self |
ContentPageBuilder:published
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn published(mut self) -> Self |
ContentPageBuilder:reading
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn reading_time_minutes(mut self, minutes : u32) -> Self |
ContentPageBuilder:required
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn required_roles(mut self, roles : Vec <String>) -> Self |
ContentPageBuilder :: fn required_entitlements(mut self, entitlements : Vec <String>) -> Self |
ContentPageBuilder:robots
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn robots(mut self, robots : impl Into <String>) -> Self |
ContentPageBuilder:role
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn role_access(mut self, roles : Vec <String>) -> Self |
ContentPageBuilder:seo
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn seo_title(mut self, title : impl Into <String>) -> Self |
ContentPageBuilder :: fn seo_description(mut self, description : impl Into <String>) -> Self |
ContentPageBuilder:slug
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn slug(mut self, slug : impl Into <String>) -> Self |
ContentPageBuilder:sort
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn sort_order(mut self, order : i32) -> Self |
ContentPageBuilder:status
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn status(mut self, status : PageStatus) -> Self |
ContentPageBuilder:tag
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn tag(mut self, tag : impl Into <String>) -> Self |
ContentPageBuilder:tags
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn tags(mut self, tags : Vec <String>) -> Self |
ContentPageBuilder:template
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn template_key(mut self, key : impl Into <String>) -> Self |
ContentPageBuilder:title
ContentPage model for CMS pages and blog posts.
| Item |
|---|
ContentPageBuilder :: fn title(mut self, title : impl Into <String>) -> Self |
redirect (other)
Redirect model for URL redirects.
| Item |
|---|
pub const MAX_HOPS: usize |
Redirect:Redirect
Redirect model for URL redirects.
| Item |
|---|
pub struct Redirect |
Redirect:builder
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn builder() -> RedirectBuilder |
Redirect:created
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn created_at(& self) -> DateTime <Utc> |
Redirect:deleted
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn deleted_at(& self) -> Option <DateTime <Utc>> |
Redirect:id
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn id(& self) -> Uuid |
Redirect:is
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn is_permanent(& self) -> bool |
Redirect :: fn is_temporary(& self) -> bool |
Redirect:matches
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn matches_path(& self, path : & str) -> bool |
Redirect:restore
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn restore(& mut self) |
Redirect:soft
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn soft_delete(& mut self) |
Redirect:status
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn status(& self) -> RedirectStatus |
Redirect :: fn status_code(& self) -> u16 |
Redirect:updated
Redirect model for URL redirects.
| Item |
|---|
Redirect :: fn updated_at(& self) -> DateTime <Utc> |
RedirectBuilder
Redirect model for URL redirects.
| Item |
|---|
pub struct RedirectBuilder |
RedirectBuilder :: fn new() -> Self |
RedirectBuilder :: fn from_path(mut self, path : impl Into <String>) -> Self |
RedirectBuilder :: fn to_path(mut self, path : impl Into <String>) -> Self |
RedirectBuilder :: fn redirect(self, from : impl Into <String>, to : impl Into <String>) -> Self |
RedirectBuilder :: fn permanent(mut self) -> Self |
RedirectBuilder :: fn temporary(mut self) -> Self |
RedirectBuilder :: fn build(self) -> Redirect |
RedirectError
Redirect model for URL redirects.
| Item |
|---|
pub enum RedirectError |
fn validate_paths(from : & str, to : & str) -> Result <(), RedirectError> |
async fn check_cycle(pool : & PgPool, from : & str, to : & str, excluding_id : Option <Uuid>,) -> Result <(), RedirectError> |
async fn resolve(pool : & PgPool, from : & str) -> Result <Option <(String, bool)>, RedirectError> |
RedirectStatus
Redirect model for URL redirects.
| Item |
|---|
pub enum RedirectStatus |
RedirectStatus :: fn status_code(& self) -> u16 |
snapshot (other)
Publishing snapshot creation and verification.
| Item |
|---|
pub const SNAPSHOT_VERSION: & str |
pub const SNAPSHOT_VERSION_WITH_TRANSLATIONS: & str |
fn unpublish_page(page : & mut ContentPage) |
fn archive_page(page : & mut ContentPage) |
BlockSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct BlockSnapshot |
BlockSnapshot :: fn from_block(block : & ContentBlock) -> Self |
BlogSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct BlogSnapshot |
LocaleSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct LocaleSnapshot |
PageSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct PageSnapshot |
PageSnapshot :: fn from_page(page : & ContentPage) -> Self |
PublishSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct PublishSnapshot |
PublishSnapshot :: fn create(page : & ContentPage, blocks : & ContentBlock) -> Self |
PublishSnapshot :: fn create_with_translations(page : & ContentPage, blocks : & ContentBlock, translations : Vec <LocaleSnapshot>,) -> Self |
PublishSnapshot :: fn has_translations(& self) -> bool |
PublishSnapshot :: fn calculate_checksum(& self) -> String |
PublishSnapshot :: fn verify_checksum(& self) -> bool |
PublishSnapshot :: fn to_json(& self) -> JsonValue |
PublishSnapshot :: fn from_json(value : & JsonValue) -> Option <Self> |
PublishSnapshot :: fn block_count(& self) -> usize |
PublishSnapshot :: fn has_blocks(& self) -> bool |
fn publish_page(page : & mut ContentPage, blocks : & ContentBlock, published_by : Uuid,) -> PublishSnapshot |
SeoSnapshot
Publishing snapshot creation and verification.
| Item |
|---|
pub struct SeoSnapshot |
PageVersion
Page version history.
| Item |
|---|
pub struct PageVersion |
PageVersion :: fn create(page : & ContentPage, blocks : & ContentBlock, version_number : i32, reason : VersionReason, saved_by_id : Option <Uuid>, change_summary : String,) -> Self |
PageVersion :: fn snapshot_json(& self) -> JsonValue |
PageVersion :: fn verify(& self) -> bool |
PageVersion :: fn is_published_version(& self) -> bool |
fn apply_version(page : & mut ContentPage, version : & PageVersion) |
VersionReason
Page version history.
| Item |
|---|
pub enum VersionReason |
VersionReason :: fn as_str(& self) -> & 'static str |
VersionReason :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
VersionReason :: fn from_str(s : & str) -> Result <Self, Self::Err> |
How to use it
From this crate's own rustdoc:
use content_cms::{
ContentPage, ContentBlock, BlogCategory, Redirect,
PageType, PageStatus, AccessLevel,
snapshot::publish_page,
};
use uuid::Uuid;
// Create a blog post
let mut post = ContentPage::builder()
.slug("hello-world")
.title("Hello World")
.post()
.excerpt("My first blog post")
.seo_description("An introduction to our blog")
.build();
// Add content blocks
let blocks = vec![
ContentBlock::builder()
.page(post.id)
.hero()
.data(serde_json::json!({
"title": "Welcome to My Blog",
"background_url": "/images/hero.jpg"
}))
.sequence(0)
.build(),
ContentBlock::builder()
.page(post.id)
.rich_text()
.data(serde_json::json!({
"content": "<p>This is my first post...</p>"
}))
.sequence(1)
.build(),
];
// Publish the post
let publisher_id = Uuid::new_v4();
let snapshot = publish_page(&mut post, &blocks, publisher_id);
assert!(post.is_published());
assert!(snapshot.verify_checksum());
Module structure
content_cms
blockblock::block_typescategoryenumserrorlifecyclepageredirectsnapshotversion
flowchart TD n_content_cms["content_cms"] n_content_cms --> n_block["block"] n_block --> n_block__block_types["block_types"] n_content_cms --> n_category["category"] n_content_cms --> n_enums["enums"] n_content_cms --> n_error["error"] n_content_cms --> n_lifecycle["lifecycle"] n_content_cms --> n_page["page"] n_content_cms --> n_redirect["redirect"] n_content_cms --> n_snapshot["snapshot"] n_content_cms --> n_version["version"]
Public surface
`block`
| Item | What it is |
|---|---|
pub struct ContentBlock | A content block attached to a page. |
ContentBlock :: fn builder() -> ContentBlockBuilder | Create a new block builder. |
ContentBlock :: fn is_for_page(& self, page_id : Uuid) -> bool | Check if this block belongs to the given page. |
ContentBlock :: fn is_type(& self, block_type : & str) -> bool | Check if this block matches the given type. |
ContentBlock :: fn is_active(& self) -> bool | Check if this block is active (should be rendered). |
ContentBlock :: fn is_inactive(& self) -> bool | Check if this block is inactive (hidden). |
ContentBlock :: fn get_string(& self, key : & str) -> Option <& str> | Get data field as string, if present. |
ContentBlock :: fn get_i64(& self, key : & str) -> Option <i64> | Get data field as i64, if present. |
ContentBlock :: fn get_bool(& self, key : & str) -> Option <bool> | Get data field as bool, if present. |
ContentBlock :: fn id(& self) -> Uuid | — |
ContentBlock :: fn created_at(& self) -> DateTime <Utc> | — |
ContentBlock :: fn updated_at(& self) -> DateTime <Utc> | — |
ContentBlock :: fn deleted_at(& self) -> Option <DateTime <Utc>> | — |
ContentBlock :: fn soft_delete(& mut self) | Mark as soft-deleted. |
ContentBlock :: fn restore(& mut self) | Restore from soft-deleted state. |
pub struct ContentBlockBuilder | Builder for ContentBlock. |
ContentBlockBuilder :: fn new() -> Self | Create a new builder. |
ContentBlockBuilder :: fn page(mut self, page_id : Uuid) -> Self | Set the parent page. |
ContentBlockBuilder :: fn block_type(mut self, block_type : impl Into <String>) -> Self | Set the block type. |
ContentBlockBuilder :: fn rich_text(self) -> Self | Set block type to rich_text. |
ContentBlockBuilder :: fn heading(self) -> Self | Set block type to heading. |
ContentBlockBuilder :: fn image(self) -> Self | Set block type to image. |
ContentBlockBuilder :: fn image_gallery(self) -> Self | Set block type to image_gallery. |
ContentBlockBuilder :: fn hero(self) -> Self | Set block type to hero. |
ContentBlockBuilder :: fn cta(self) -> Self | Set block type to cta. |
ContentBlockBuilder :: fn embed(self) -> Self | Set block type to embed. |
ContentBlockBuilder :: fn divider(self) -> Self | Set block type to divider. |
ContentBlockBuilder :: fn data(mut self, data : JsonValue) -> Self | Set the block data. |
ContentBlockBuilder :: fn sequence(mut self, sequence : u32) -> Self | Set the sequence (order within page). |
ContentBlockBuilder :: fn active(mut self, is_active : bool) -> Self | Set whether the block is active. |
ContentBlockBuilder :: fn inactive(mut self) -> Self | Set block as inactive (hidden). |
ContentBlockBuilder :: fn build(self) -> ContentBlock | Build the content block |
`block::block_types`
| Item | What it is |
|---|---|
pub const RICH_TEXT: & str | Rich text HTML content. |
pub const HEADING: & str | Heading (H1-H6). |
pub const IMAGE: & str | Single image with optional caption. |
pub const IMAGE_GALLERY: & str | Image gallery with multiple images. |
pub const HERO: & str | Hero banner with background, title, CTA. |
pub const CTA: & str | Call-to-action button. |
pub const EMBED: & str | Embedded content (YouTube, etc.). |
pub const DIVIDER: & str | Visual divider/separator. |
pub const ALL: & & str | All built-in block types. |
fn is_builtin(block_type : & str) -> bool | Check if a block type is built-in. |
`category`
| Item | What it is |
|---|---|
pub struct BlogCategory | A category for organizing blog posts. |
BlogCategory :: fn builder() -> BlogCategoryBuilder | Create a new category builder. |
BlogCategory :: fn matches_slug(& self, slug : & str) -> bool | Check if this category matches the given slug. |
BlogCategory :: fn slugify(name : & str) -> String | Generate a slug from a name |
BlogCategory :: fn id(& self) -> Uuid | — |
BlogCategory :: fn created_at(& self) -> DateTime <Utc> | — |
BlogCategory :: fn updated_at(& self) -> DateTime <Utc> | — |
BlogCategory :: fn deleted_at(& self) -> Option <DateTime <Utc>> | — |
BlogCategory :: fn soft_delete(& mut self) | Mark as soft-deleted. |
BlogCategory :: fn restore(& mut self) | Restore from soft-deleted state. |
pub struct BlogCategoryBuilder | Builder for BlogCategory. |
BlogCategoryBuilder :: fn new() -> Self | Create a new builder. |
BlogCategoryBuilder :: fn name(mut self, name : impl Into <String>) -> Self | Set the display name. |
BlogCategoryBuilder :: fn slug(mut self, slug : impl Into <String>) -> Self | Set the slug (URL-friendly identifier). |
BlogCategoryBuilder :: fn description(mut self, description : impl Into <String>) -> Self | Set the description. |
BlogCategoryBuilder :: fn color(mut self, color : impl Into <String>) -> Self | Set the color (hex format). |
BlogCategoryBuilder :: fn sort_order(mut self, order : i32) -> Self | Set sort order. |
BlogCategoryBuilder :: fn build(self) -> BlogCategory | Build the category |
`enums`
| Item | What it is |
|---|---|
pub enum PageType | Type of content page. |
PageType :: fn as_str(& self) -> & 'static str | Returns the string representation. |
PageType :: fn is_post(& self) -> bool | Check if this is a blog post. |
PageType :: fn is_page(& self) -> bool | Check if this is a regular page. |
PageType :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
PageType :: fn from_str(s : & str) -> Result <Self, Self::Err> | — |
pub enum PageStatus | Publishing status of a content page. |
PageStatus :: fn as_str(& self) -> & 'static str | Returns the string representation. |
PageStatus :: fn is_published(& self) -> bool | Check if the page is published. |
PageStatus :: fn is_draft(& self) -> bool | Check if the page is a draft. |
PageStatus :: fn is_archived(& self) -> bool | Check if the page is archived. |
PageStatus :: fn is_visible(& self) -> bool | Check if the page is visible to public (published only). |
PageStatus :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
PageStatus :: fn from_str(s : & str) -> Result <Self, Self::Err> | — |
pub enum AccessLevel | Access control level for content pages. |
AccessLevel :: fn as_str(& self) -> & 'static str | Returns the string representation. |
AccessLevel :: fn requires_auth(& self) -> bool | Check if this level requires authentication. |
AccessLevel :: fn is_public(& self) -> bool | Check if this is public access. |
AccessLevel :: fn is_role_based(& self) -> bool | Check if this requires role-based access. |
AccessLevel :: fn is_entitlement_based(& self) -> bool | Check if this requires entitlement check. |
AccessLevel :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
AccessLevel :: fn from_str(s : & str) -> Result <Self, Self::Err> | — |
`error`
| Item | What it is |
|---|---|
pub enum CMSError | CMS-specific errors. |
CMSError :: fn page_not_found(id : Uuid) -> Self | Create a page not found error. |
CMSError :: fn page_not_found_by_slug(slug : impl Into <String>) -> Self | Create a page not found by slug error. |
CMSError :: fn block_not_found(id : Uuid) -> Self | Create a block not found error. |
CMSError :: fn category_not_found(id : Uuid) -> Self | Create a category not found error. |
CMSError :: fn category_not_found_by_slug(slug : impl Into <String>) -> Self | Create a category not found by slug error. |
CMSError :: fn redirect_not_found(id : Uuid) -> Self | Create a redirect not found error. |
CMSError :: fn redirect_not_found_by_path(path : impl Into <String>) -> Self | Create a redirect not found by path error. |
CMSError :: fn duplicate_slug(slug : impl Into <String>) -> Self | Create a duplicate slug error. |
CMSError :: fn duplicate_redirect_path(path : impl Into <String>) -> Self | Create a duplicate redirect path error. |
CMSError :: fn invalid_slug(slug : impl Into <String>) -> Self | Create an invalid slug error. |
CMSError :: fn invalid_block_type(block_type : impl Into <String>) -> Self | Create an invalid block type error. |
CMSError :: fn block_validation_failed(block_type : impl Into <String>, message : impl Into <String>,) -> Self | Create a block validation failed error. |
CMSError :: fn cannot_publish(reason : impl Into <String>) -> Self | Create a cannot publish error. |
CMSError :: fn not_published(id : Uuid) -> Self | Create a not published error. |
CMSError :: fn access_denied(slug : impl Into <String>, reason : impl Into <String>) -> Self | Create an access denied error. |
CMSError :: fn invalid_seo_field(field : impl Into <String>, message : impl Into <String>) -> Self | Create an invalid SEO field error. |
CMSError :: fn version_page_mismatch(version_id : Uuid, version_page_id : Uuid, page_id : Uuid) -> Self | Create a version/page mismatch error. |
`lifecycle`
| Item | What it is |
|---|---|
pub enum RenderMode | Which side of the version pair to render. |
pub enum DraftState | Whether a page's draft has changes the public hasn't seen yet |
DraftState :: fn as_str(& self) -> & 'static str | Stable string form — used by consumers to key a template branch or a log line. |
DraftState :: fn has_unpublished_changes(& self) -> bool | True when there is a draft the operator could publish or discard (the editor's State A). |
fn draft_state(page : & ContentPage) -> DraftState | Classify a page's draft-vs-published state from its version pair. |
fn draft_state_from(published_version_id : Option <Uuid>, draft_version_id : Option <Uuid>,) -> DraftState | Classify the draft-vs-published state directly from the two pointer values — for consumers (e.g |
fn save_draft(page : & mut ContentPage, draft_version : & PageVersion) -> Result <(), CMSError> | Record a draft save: advance draft_version_id to the just-saved version |
fn publish_draft(page : & mut ContentPage, publish_version : & PageVersion, published_by : Uuid,) -> Result <(), CMSError> | Publish the draft: swap published_version_id to the publish version in one step |
fn rollback(page : & mut ContentPage, target : & PageVersion, published_by : Uuid,) -> Result <(), CMSError> | Roll the public back to an earlier version: repoint published_version_id at target |
fn get_page_for_render(page : & ContentPage, published_version : Option <& PageVersion>, mode : RenderMode,) -> Result <ContentPage, CMSError> | Build the ContentPage to render for mode |
`page`
| Item | What it is |
|---|---|
pub struct ContentPage | A content page supporting both regular pages and blog posts. |
ContentPage :: fn builder() -> ContentPageBuilder | Create a new page builder. |
ContentPage :: fn is_post(& self) -> bool | Check if this is a blog post. |
ContentPage :: fn is_page(& self) -> bool | Check if this is a regular page. |
ContentPage :: fn is_published(& self) -> bool | Check if the page is published. |
ContentPage :: fn is_draft(& self) -> bool | Check if the page is a draft. |
ContentPage :: fn is_archived(& self) -> bool | Check if the page is archived. |
ContentPage :: fn is_public(& self) -> bool | Check if the page is publicly accessible. |
ContentPage :: fn can_access(& self, user_id : Option <Uuid>, user_roles : & String, is_staff : bool) -> bool | Check if a user can access this page |
ContentPage :: fn matches_slug(& self, slug : & str) -> bool | Check if the page matches the given slug. |
ContentPage :: fn effective_seo_title(& self) -> & str | Get the effective SEO title (falls back to title). |
ContentPage :: fn has_snapshot(& self) -> bool | Check if the page has a published snapshot. |
ContentPage :: fn depth(& self) -> usize | Tree-depth of this page in the slug hierarchy |
fn depth_of_slug(slug : & str) -> usize | Derive the tree-depth of a CMS page from its slug |
ContentPage :: fn id(& self) -> Uuid | — |
ContentPage :: fn created_at(& self) -> DateTime <Utc> | — |
ContentPage :: fn updated_at(& self) -> DateTime <Utc> | — |
ContentPage :: fn deleted_at(& self) -> Option <DateTime <Utc>> | — |
ContentPage :: fn soft_delete(& mut self) | Mark as soft-deleted. |
ContentPage :: fn restore(& mut self) | Restore from soft-deleted state. |
pub struct ContentPageBuilder | Builder for ContentPage. |
ContentPageBuilder :: fn new() -> Self | Create a new builder. |
ContentPageBuilder :: fn slug(mut self, slug : impl Into <String>) -> Self | Set the slug. |
ContentPageBuilder :: fn title(mut self, title : impl Into <String>) -> Self | Set the title. |
ContentPageBuilder :: fn page(mut self) -> Self | Set page type to Page. |
ContentPageBuilder :: fn post(mut self) -> Self | Set page type to Post. |
ContentPageBuilder :: fn page_type(mut self, page_type : PageType) -> Self | Set the page type. |
ContentPageBuilder :: fn draft(mut self) -> Self | Set status to Draft. |
ContentPageBuilder :: fn published(mut self) -> Self | Set status to Published. |
ContentPageBuilder :: fn archived(mut self) -> Self | Set status to Archived. |
ContentPageBuilder :: fn status(mut self, status : PageStatus) -> Self | Set the status. |
ContentPageBuilder :: fn public(mut self) -> Self | Set access level to Public. |
ContentPageBuilder :: fn authenticated(mut self) -> Self | Set access level to Authenticated. |
ContentPageBuilder :: fn role_access(mut self, roles : Vec <String>) -> Self | Set access level to Role with required roles. |
ContentPageBuilder :: fn entitlement_access(mut self, entitlements : Vec <String>) -> Self | Set access level to Entitlement with required entitlements. |
ContentPageBuilder :: fn access_level(mut self, level : AccessLevel) -> Self | Set the access level. |
ContentPageBuilder :: fn required_roles(mut self, roles : Vec <String>) -> Self | Set required roles. |
ContentPageBuilder :: fn required_entitlements(mut self, entitlements : Vec <String>) -> Self | Set required entitlements. |
ContentPageBuilder :: fn seo_title(mut self, title : impl Into <String>) -> Self | Set SEO title. |
ContentPageBuilder :: fn seo_description(mut self, description : impl Into <String>) -> Self | Set SEO description. |
ContentPageBuilder :: fn og_image_url(mut self, url : impl Into <String>) -> Self | Set Open Graph image URL. |
ContentPageBuilder :: fn canonical_url(mut self, url : impl Into <String>) -> Self | Set canonical URL. |
ContentPageBuilder :: fn robots(mut self, robots : impl Into <String>) -> Self | Set robots meta tag. |
ContentPageBuilder :: fn sort_order(mut self, order : i32) -> Self | Set sort order. |
ContentPageBuilder :: fn indexable(mut self, indexable : bool) -> Self | Set whether indexable. |
ContentPageBuilder :: fn template_key(mut self, key : impl Into <String>) -> Self | Set template key. |
ContentPageBuilder :: fn author(mut self, author_id : Uuid) -> Self | Set author (for blog posts). |
ContentPageBuilder :: fn excerpt(mut self, excerpt : impl Into <String>) -> Self | Set excerpt (for blog posts). |
ContentPageBuilder :: fn featured_image_url(mut self, url : impl Into <String>) -> Self | Set featured image URL (for blog posts). |
ContentPageBuilder :: fn reading_time_minutes(mut self, minutes : u32) -> Self | Set reading time in minutes (for blog posts). |
ContentPageBuilder :: fn category(mut self, category_id : Uuid) -> Self | Set category (for blog posts). |
ContentPageBuilder :: fn tags(mut self, tags : Vec <String>) -> Self | Set tags (for blog posts). |
ContentPageBuilder :: fn tag(mut self, tag : impl Into <String>) -> Self | Add a tag. |
ContentPageBuilder :: fn metadata(mut self, metadata : JsonValue) -> Self | Set metadata. |
ContentPageBuilder :: fn build(self) -> ContentPage | Build the content page |
`redirect`
| Item | What it is |
|---|---|
pub enum RedirectStatus | HTTP redirect status codes. |
RedirectStatus :: fn status_code(& self) -> u16 | Get the HTTP status code. |
pub struct Redirect | A URL redirect rule. |
Redirect :: fn builder() -> RedirectBuilder | Create a new redirect builder. |
Redirect :: fn matches_path(& self, path : & str) -> bool | Check if this redirect matches the given path. |
Redirect :: fn status(& self) -> RedirectStatus | Get the redirect status (permanent or temporary). |
Redirect :: fn status_code(& self) -> u16 | Get the HTTP status code for this redirect. |
Redirect :: fn is_permanent(& self) -> bool | Check if this is a permanent (301) redirect. |
Redirect :: fn is_temporary(& self) -> bool | Check if this is a temporary (302) redirect. |
Redirect :: fn id(& self) -> Uuid | — |
Redirect :: fn created_at(& self) -> DateTime <Utc> | — |
Redirect :: fn updated_at(& self) -> DateTime <Utc> | — |
Redirect :: fn deleted_at(& self) -> Option <DateTime <Utc>> | — |
Redirect :: fn soft_delete(& mut self) | Mark as soft-deleted. |
Redirect :: fn restore(& mut self) | Restore from soft-deleted state. |
pub struct RedirectBuilder | Builder for Redirect. |
RedirectBuilder :: fn new() -> Self | Create a new builder. |
RedirectBuilder :: fn from_path(mut self, path : impl Into <String>) -> Self | Set the source path. |
RedirectBuilder :: fn to_path(mut self, path : impl Into <String>) -> Self | Set the destination path. |
RedirectBuilder :: fn redirect(self, from : impl Into <String>, to : impl Into <String>) -> Self | Set both from and to paths. |
RedirectBuilder :: fn permanent(mut self) -> Self | Set as permanent (301) redirect. |
RedirectBuilder :: fn temporary(mut self) -> Self | Set as temporary (302) redirect. |
RedirectBuilder :: fn build(self) -> Redirect | Build the redirect |
pub const MAX_HOPS: usize | Maximum redirect chain depth before check_cycle / resolve give up + return RedirectError::TooLong |
pub enum RedirectError | Errors from the SQL-backed redirect chain helpers |
fn validate_paths(from : & str, to : & str) -> Result <(), RedirectError> | Validate a redirect's (from, to) paths |
async fn check_cycle(pool : & PgPool, from : & str, to : & str, excluding_id : Option <Uuid>,) -> Result <(), RedirectError> | Check that inserting or updating a redirect (from → to) doesn't create a chain longer than MAX_HOPS or a cycle |
async fn resolve(pool : & PgPool, from : & str) -> Result <Option <(String, bool)>, RedirectError> | Resolve a request path against the redirect table |
`snapshot`
| Item | What it is |
|---|---|
pub const SNAPSHOT_VERSION: & str | Snapshot version for compatibility tracking |
pub const SNAPSHOT_VERSION_WITH_TRANSLATIONS: & str | Snapshot version that captures per-locale translations (PublishSnapshot::create_with_translations, Sprint 0.47) |
pub struct PublishSnapshot | A published snapshot of a page and its blocks. |
pub struct PageSnapshot | Page data within a snapshot. |
pub struct SeoSnapshot | SEO data within a snapshot. |
pub struct BlogSnapshot | Blog-specific data within a snapshot. |
pub struct LocaleSnapshot | One locale's content within a snapshot (Sprint 0.47) |
pub struct BlockSnapshot | Block data within a snapshot. |
PublishSnapshot :: fn create(page : & ContentPage, blocks : & ContentBlock) -> Self | Create a legacy ("1.0") snapshot from a page and its blocks — no per-locale translations |
PublishSnapshot :: fn create_with_translations(page : & ContentPage, blocks : & ContentBlock, translations : Vec <LocaleSnapshot>,) -> Self | Create a translation-capturing ("1.1") snapshot (Sprint 0.47) |
PublishSnapshot :: fn has_translations(& self) -> bool | True if this snapshot captured per-locale translations ("1.1"+) |
PublishSnapshot :: fn calculate_checksum(& self) -> String | Calculate SHA-256 checksum of snapshot content |
PublishSnapshot :: fn verify_checksum(& self) -> bool | Verify the snapshot checksum. |
PublishSnapshot :: fn to_json(& self) -> JsonValue | Convert to JSON value for storage. |
PublishSnapshot :: fn from_json(value : & JsonValue) -> Option <Self> | Parse from JSON value. |
PublishSnapshot :: fn block_count(& self) -> usize | Get the number of blocks in this snapshot. |
PublishSnapshot :: fn has_blocks(& self) -> bool | Check if this snapshot has any blocks. |
PageSnapshot :: fn from_page(page : & ContentPage) -> Self | Create from a ContentPage. |
BlockSnapshot :: fn from_block(block : & ContentBlock) -> Self | Create from a ContentBlock. |
fn publish_page(page : & mut ContentPage, blocks : & ContentBlock, published_by : Uuid,) -> PublishSnapshot | Helper to publish a page. |
fn unpublish_page(page : & mut ContentPage) | Helper to unpublish a page |
fn archive_page(page : & mut ContentPage) | Helper to archive a page. |
`version`
| Item | What it is |
|---|---|
pub enum VersionReason | Why a version row exists. |
VersionReason :: fn as_str(& self) -> & 'static str | String form for storage / serialization. |
VersionReason :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
VersionReason :: fn from_str(s : & str) -> Result <Self, Self::Err> | — |
pub struct PageVersion | A row from cms_page_versions |
PageVersion :: fn create(page : & ContentPage, blocks : & ContentBlock, version_number : i32, reason : VersionReason, saved_by_id : Option <Uuid>, change_summary : String,) -> Self | Build an in-memory PageVersion for INSERT |
PageVersion :: fn snapshot_json(& self) -> JsonValue | Convenience: serialize the snapshot for storing in the JSONB column |
PageVersion :: fn verify(& self) -> bool | Verify the snapshot's checksum is consistent. |
PageVersion :: fn is_published_version(& self) -> bool | True if this version captures a published state. |
fn apply_version(page : & mut ContentPage, version : & PageVersion) | Apply the snapshot from a PageVersion to a ContentPage in place |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
CMSError | error::CMSError |
{AccessLevel,PageStatus,PageType} | enums::{AccessLevel,PageStatus,PageType} |
{BlockSnapshot,BlogSnapshot,LocaleSnapshot,PageSnapshot,PublishSnapshot,SeoSnapshot,SNAPSHOT_VERSION,SNAPSHOT_VERSION_WITH_TRANSLATIONS,} | snapshot::{BlockSnapshot,BlogSnapshot,LocaleSnapshot,PageSnapshot,PublishSnapshot,SeoSnapshot,SNAPSHOT_VERSION,SNAPSHOT_VERSION_WITH_TRANSLATIONS,} |
{BlogCategory,BlogCategoryBuilder} | category::{BlogCategory,BlogCategoryBuilder} |
{HasId,SoftDeletable,Timestamped} | foundation_basemodels::{HasId,SoftDeletable,Timestamped} |
{Redirect,RedirectBuilder,RedirectStatus} | redirect::{Redirect,RedirectBuilder,RedirectStatus} |
{apply_version,PageVersion,VersionReason} | version::{apply_version,PageVersion,VersionReason} |
{block_types,ContentBlock,ContentBlockBuilder} | block::{block_types,ContentBlock,ContentBlockBuilder} |
{depth_of_slug,ContentPage,ContentPageBuilder} | page::{depth_of_slug,ContentPage,ContentPageBuilder} |
{draft_state,draft_state_from,get_page_for_render,publish_draft,rollback,save_draft,DraftState,RenderMode,} | lifecycle::{draft_state,draft_state_from,get_page_for_render,publish_draft,rollback,save_draft,DraftState,RenderMode,} |
Boundary
Reaches into foundation.
Shares tier content with 5 other crates: content-assets, content-calendar, content-calendar-recurrence, content-directory-listing, content-notes.
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | content |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/content/cms |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_content["content"] --> n_foundation["foundation"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-basemodels` | foundation | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
chrono | ^0.4 | serde | no | always |
hex | ^0.4 | — | no | always |
serde | ^1 | derive | no | always |
serde_json | ^1 | — | no | always |
sha2 | ^0.10 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full | no | always |
uuid | ^1 | v4, serde | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
tokio-test | ^0.4 | — | no | always |
Build. None.
Depended on by. 2 workspace crates.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_cms["application-cms"] -->|uses| SELF n_platform_wasm_ui["platform-wasm-ui"] -->|uses| SELF SELF["content-cms"] SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
default | — | yes |
flowchart LR n_default["default"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | content_cms | `src/lib.rs` |
Error model
| Error type | Named by |
|---|---|
CMSError | get_page_for_render, publish_draft, rollback, save_draft |
RedirectError | check_cycle, resolve, validate_paths |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | yes |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
2 workspace crates depend on this one: application-cms, platform-wasm-ui.
Verification
| Kind | Count |
|---|---|
| Unit tests | 160 |
| Integration tests | 0 |
| Examples | 0 |
| Doctests | 1 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
block | 2 | 0 | 1 |
block::block_types | 10 | 0 | 3 |
category | 2 | 0 | 0 |
enums | 3 | 0 | 5 |
error | 1 | 0 | 0 |
lifecycle | 8 | 0 | 5 |
page | 3 | 0 | 3 |
redirect | 8 | 0 | 6 |
snapshot | 11 | 0 | 5 |
version | 3 | 0 | 2 |
What the tests establish, by name:
test_block_active_status—src/block.rstest_block_builder_basic—src/block.rstest_block_builder_with_data—src/block.rstest_block_data_accessors—src/block.rstest_block_has_id_trait—src/block.rstest_block_is_for_page—src/block.rstest_block_is_type—src/block.rstest_block_sequence—src/block.rstest_block_serialization—src/block.rstest_block_soft_deletable_trait—src/block.rstest_block_timestamped_trait—src/block.rstest_block_type_helpers—src/block.rstest_block_types_all—src/block.rstest_block_types_constants—src/block.rstest_block_types_is_builtin—src/block.rstest_category_auto_slug—src/category.rstest_category_builder_basic—src/category.rstest_category_builder_full—src/category.rstest_category_explicit_slug—src/category.rstest_category_has_id_trait—src/category.rstest_category_matches_slug—src/category.rstest_category_serialization—src/category.rstest_category_slugify—src/category.rstest_category_soft_deletable_trait—src/category.rstest_category_sorting—src/category.rstest_category_timestamped_trait—src/category.rstest_access_level_as_str—src/enums.rstest_access_level_default—src/enums.rstest_access_level_display—src/enums.rstest_access_level_is_entitlement_based—src/enums.rs- _… 130 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 201 | 225 |
Public modules with a //! block | 9 | 10 |
pie showData
title Public items with rustdoc
"Documented" : 201
"No rustdoc detected" : 24
Metrics
| Metric | Value |
|---|---|
| Rust source files | 10 |
| Source lines | 5051 |
| Code lines | 3518 |
| Public API items | 225 |
| Public modules | 10 |
| Tests | 160 |
| Examples | 0 |
| Cargo features | 1 |
| Direct runtime dependencies | 10 |
| Workspace reverse dependencies | 2 |
pie showData
title Public API by kind
"constant" : 12
"enum" : 9
"function" : 15
"method" : 174
"struct" : 15
pie showData
title Rust source composition
"Code" : 3518
"Blank or comment" : 1533
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.