Packages

Social posts module for PhoenixKit — user posts, threaded comments, tags, boards, likes/dislikes, media, mentions, and scheduling

Current section

Files

Jump to
phoenix_kit_posts lib phoenix_kit_posts schemas post_media.ex
Raw

lib/phoenix_kit_posts/schemas/post_media.ex

defmodule PhoenixKitPosts.PostMedia do
@moduledoc """
Junction schema for post media attachments.
Links posts to uploaded files (images/videos) with ordering and captions.
Enables ordered image galleries in posts with per-image captions.
## Fields
- `post_uuid` - Reference to the post
- `file_uuid` - Reference to the uploaded file (PhoenixKit.Storage.File)
- `position` - Display order (1, 2, 3, etc.)
- `caption` - Optional caption/alt text for the image
## Examples
# First image in post
%PostMedia{
post_uuid: "018e3c4a-9f6b-7890-abcd-ef1234567890",
file_uuid: "018e3c4a-1234-5678-abcd-ef1234567890",
position: 1,
caption: "Beautiful sunset at the beach"
}
# Second image
%PostMedia{
post_uuid: "018e3c4a-9f6b-7890-abcd-ef1234567890",
file_uuid: "018e3c4a-5678-1234-abcd-ef1234567890",
position: 2,
caption: nil
}
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:uuid, UUIDv7, autogenerate: true}
@foreign_key_type UUIDv7
@type t :: %__MODULE__{
uuid: UUIDv7.t() | nil,
post_uuid: UUIDv7.t(),
file_uuid: UUIDv7.t(),
position: integer(),
caption: String.t() | nil,
post: PhoenixKitPosts.Post.t() | Ecto.Association.NotLoaded.t(),
file: PhoenixKit.Modules.Storage.File.t() | Ecto.Association.NotLoaded.t(),
inserted_at: DateTime.t() | nil,
updated_at: DateTime.t() | nil
}
schema "phoenix_kit_post_media" do
field(:position, :integer)
field(:caption, :string)
belongs_to(:post, PhoenixKitPosts.Post, foreign_key: :post_uuid, references: :uuid)
belongs_to(:file, PhoenixKit.Modules.Storage.File, foreign_key: :file_uuid, references: :uuid)
timestamps(type: :utc_datetime)
end
@doc """
Changeset for creating or updating post media.
## Required Fields
- `post_uuid` - Reference to post
- `file_uuid` - Reference to file
- `position` - Display order (must be positive)
## Validation Rules
- Position must be greater than 0
- Unique constraint on (post_uuid, position) - enforced at database level
"""
def changeset(media, attrs) do
media
|> cast(attrs, [:post_uuid, :file_uuid, :position, :caption])
|> validate_required([:post_uuid, :file_uuid, :position])
|> validate_number(:position, greater_than: 0)
|> foreign_key_constraint(:post_uuid)
|> foreign_key_constraint(:file_uuid)
|> unique_constraint([:post_uuid, :position],
name: :phoenix_kit_post_media_post_uuid_position_index,
message: "position already taken for this post"
)
end
end