PhoenixKit.Modules.Publishing.Versions (PhoenixKitPublishing v0.1.9)

Copy Markdown View Source

Version management functions for the Publishing module.

Handles listing, creating, publishing, and deleting versions of publishing posts.

Summary

Functions

Creates a new version of a slug-mode post by copying from the latest version.

Creates a new version from an existing version or blank.

Deletes an entire version of a post.

Gets the published version number for a post.

Returns a %{status, title, url_slug, version} map for the given group/post/version/language tuple, or nil when any link in the chain (post → version → per-language content) is missing.

Gets the status of a specific version/language.

Lists version numbers for a post.

Publishes a version, making it the live version for the post.

Unpublishes a post by clearing its active version.

Functions

create_new_version(group_slug, source_post, params \\ %{}, opts \\ %{})

@spec create_new_version(String.t(), map(), map(), map() | keyword()) ::
  {:ok, map()} | {:error, any()}

Creates a new version of a slug-mode post by copying from the latest version.

The new version starts as draft with status: "draft". Content and metadata updates from params are applied to the new version.

Note: For more control over which version to branch from, use create_version_from/5.

create_version_from(group_slug, post_uuid, source_version, params \\ %{}, opts \\ %{})

@spec create_version_from(
  String.t(),
  String.t(),
  integer() | nil,
  map(),
  map() | keyword()
) ::
  {:ok, map()} | {:error, any()}

Creates a new version from an existing version or blank.

Parameters

  • group_slug - The publishing group slug
  • post_slug - The post slug
  • source_version - Version to copy from, or nil for blank version
  • params - Optional parameters for the new version
  • opts - Options including :scope for audit metadata

Examples

# Create blank version
iex> Publishing.Versions.create_version_from("blog", "my-post", nil, %{}, scope: scope)
{:ok, %{version: 3, ...}}

# Branch from version 1
iex> Publishing.Versions.create_version_from("blog", "my-post", 1, %{}, scope: scope)
{:ok, %{version: 3, ...}}

delete_version(group_slug, post_uuid, version, opts \\ [])

@spec delete_version(String.t(), String.t(), integer(), keyword() | map()) ::
  :ok | {:error, term()}

Deletes an entire version of a post.

Archives the version instead of permanent deletion. Refuses to delete the last remaining version or the live version.

Returns :ok on success or {:error, reason} on failure.

get_published_version(group_slug, post_slug)

Gets the published version number for a post.

get_version_metadata(group_slug, post_slug, version_number, language)

@spec get_version_metadata(String.t(), String.t(), integer(), String.t()) ::
  map() | nil

Returns a %{status, title, url_slug, version} map for the given group/post/version/language tuple, or nil when any link in the chain (post → version → per-language content) is missing.

Used by the editor and listing views to surface the version's title and URL slug for a specific language without having to load the full version + content rows.

Returns nil (not an {:error, _} tuple) on DB exceptions — the caller treats absent metadata the same as a missing version, and the exception is logged for diagnostics.

get_version_status(group_slug, post_slug, version_number, language)

Gets the status of a specific version/language.

list_versions(group_slug, post_slug)

Lists version numbers for a post.

publish_version(group_slug, post_uuid, version, opts \\ [])

@spec publish_version(String.t(), String.t(), integer(), keyword()) ::
  :ok | {:error, any()}

Publishes a version, making it the live version for the post.

  • Sets the target version status to "published" and published_at (if not already set)
  • Archives the previously published version (status -> "archived")
  • Sets post.active_version_uuid to the target version's UUID

Options

  • :source_id - ID of the source (e.g., socket.id) to include in broadcasts, allowing receivers to ignore their own messages

Examples

iex> Publishing.Versions.publish_version("blog", "my-post", 2)
:ok

iex> Publishing.Versions.publish_version("blog", "my-post", 2, source_id: "phx-abc123")
:ok

iex> Publishing.Versions.publish_version("blog", "nonexistent", 1)
{:error, :not_found}

unpublish_post(group_slug, post_uuid, opts \\ [])

@spec unpublish_post(String.t(), String.t(), keyword()) :: :ok | {:error, any()}

Unpublishes a post by clearing its active version.

  • Clears post.active_version_uuid
  • Sets the previously-active version status to :target_status opt (default "draft"; pass "archived" to archive instead). The UI's "archived" status flows through here so the version's row should actually carry "archived", otherwise the UI label and the DB state diverge (the admin listing shows "Archived" but the underlying version is "draft").

Options

  • :source_id - ID of the source to include in broadcasts
  • :target_status - final status for the previously-active version ("draft" or "archived"; default "draft")

Examples

iex> Publishing.Versions.unpublish_post("blog", post_uuid)
:ok

iex> Publishing.Versions.unpublish_post("blog", post_uuid, target_status: "archived")
:ok

iex> Publishing.Versions.unpublish_post("blog", "nonexistent")
{:error, :not_found}