PhoenixKitPosts (PhoenixKitPosts v0.1.3)

Copy Markdown View Source

Context for managing posts, likes, tags, and groups.

Provides complete API for the social posts system including CRUD operations, counter cache management, tag assignment, and group organization. Comments are now handled by the standalone PhoenixKitComments module.

Features

  • Post Management: Create, update, delete, publish, schedule posts
  • Like System: Like/unlike posts, check like status
  • Comment System: Nested threaded comments with unlimited depth
  • Tag System: Hashtag categorization with auto-slugification
  • Group System: User collections for organizing posts
  • Media Attachments: Multiple images per post with ordering
  • Publishing: Draft/public/unlisted/scheduled status management
  • Analytics: View tracking (future feature)

Examples

# Create a post
{:ok, post} = PhoenixKitPosts.create_post(user_uuid, %{
  title: "My First Post",
  content: "Hello world!",
  type: "post",
  status: "draft"
})

# Publish a post
{:ok, post} = PhoenixKitPosts.publish_post(post)

# Like a post
{:ok, like} = PhoenixKitPosts.like_post(post.uuid, user_uuid)

# Add a comment
{:ok, comment} = PhoenixKitPosts.create_comment(post.uuid, user_uuid, %{
  content: "Great post!"
})

# Create a group
{:ok, group} = PhoenixKitPosts.create_group(user_uuid, %{
  name: "Travel Photos",
  description: "My adventures"
})

Summary

Functions

Adds multiple posts to a group in a single transaction.

Adds tags to a post.

Counts posts matching the given filter options.

Creates a user group.

Creates a new post.

Decrements the comment counter for a post.

Decrements the dislike counter for a post.

Decrements the like counter for a post.

Deletes a group.

Deletes a post and all related data (cascades to media, likes, comments, etc.).

Detaches media from a post.

Detaches media from a post by PostMedia ID.

Disables the Posts module.

User dislikes a post.

Reverts a post to draft status.

Enables the Posts module.

Checks if the Posts module is enabled.

Finds or creates a tag by name.

Gets the current Posts module configuration and stats.

Gets the featured image for a post (PostMedia with position 1).

Gets a single group by ID with optional preloads.

Gets a single group by ID with optional preloads.

Gets a single post by ID with optional preloads.

Gets a single post by ID with optional preloads.

Gets a single post by slug.

Increments the comment counter for a post.

Increments the dislike counter for a post.

Increments the like counter for a post.

Increments the view counter for a post.

User likes a post.

Lists all groups ordered by name.

Lists popular tags by usage count.

Lists all dislikes for a post.

Lists all likes for a post.

Lists media for a post (ordered by position).

Lists mentioned users in a post.

Lists posts with optional filtering and pagination.

Lists public posts only.

Callback invoked by the Comments module when a comment is created on a post. Increments the post's denormalized comment_count.

Callback invoked by the Comments module when a comment is deleted from a post. Decrements the post's denormalized comment_count.

Parses hashtags from text.

Checks if a user has disliked a post.

Checks if a user has liked a post.

Processes scheduled posts that are ready to be published.

Publishes a post (makes it public).

Removes the featured image from a post.

Removes a mention from a post.

Removes a post from a group.

Removes a tag from a post.

Resolves post titles and admin paths for a list of resource IDs.

Schedules a post for future publishing.

Sets the featured image for a post (PostMedia with position 1).

User removes dislike from a post.

User unlikes a post.

Unschedules a post, reverting it to draft status.

Updates a group.

Updates an existing post.

Functions

add_mention_to_post(post_uuid, user_uuid, mention_type \\ "mention")

Adds a mention to a post.

add_post_to_group(post_uuid, group_uuid, opts \\ [])

Adds a post to a group.

add_posts_to_group(post_uuids, group_uuid, opts \\ [])

Adds multiple posts to a group in a single transaction.

add_tags_to_post(post, tag_names)

Adds tags to a post.

Creates tags if they don't exist, then assigns them to the post. Updates usage counters for tags.

attach_media(post_uuid, file_uuid, opts \\ [])

Attaches media to a post.

count_posts(opts \\ [])

Counts posts matching the given filter options.

Accepts the same filter options as list_posts/1 (:user_uuid, :status, :type, :search) but ignores pagination options.

create_group(user_uuid, attrs)

Creates a user group.

create_post(user_uuid, attrs)

Creates a new post.

Parameters

  • user_uuid - Owner UUID (UUIDv7 string)
  • attrs - Post attributes (title, content, type, status, etc.)

Examples

iex> create_post("019145a1-...", %{title: "Test", content: "Content", type: "post"})
{:ok, %Post{}}

iex> create_post("019145a1-...", %{title: "", content: ""})
{:error, %Ecto.Changeset{}}

decrement_comment_count(post)

Decrements the comment counter for a post.

Examples

iex> decrement_comment_count(post)
{1, nil}

decrement_dislike_count(post)

Decrements the dislike counter for a post.

Examples

iex> decrement_dislike_count(post)
{1, nil}

decrement_like_count(post)

Decrements the like counter for a post.

Examples

iex> decrement_like_count(post)
{1, nil}

delete_group(group)

Deletes a group.

delete_post(post)

Deletes a post and all related data (cascades to media, likes, comments, etc.).

Parameters

  • post - Post struct to delete

Examples

iex> delete_post(post)
{:ok, %Post{}}

iex> delete_post(post)
{:error, %Ecto.Changeset{}}

detach_media(post_uuid, file_uuid)

Detaches media from a post.

detach_media_by_uuid(media_uuid)

Detaches media from a post by PostMedia ID.

disable_system()

Disables the Posts module.

Examples

iex> disable_system()
{:ok, %Setting{}}

dislike_post(post_uuid, user_uuid)

User dislikes a post.

draft_post(post)

Reverts a post to draft status.

Examples

iex> draft_post(post)
{:ok, %Post{status: "draft"}}

enable_system()

Enables the Posts module.

Examples

iex> enable_system()
{:ok, %Setting{}}

enabled?()

Checks if the Posts module is enabled.

Examples

iex> enabled?()
true

find_or_create_tag(name)

Finds or creates a tag by name.

Automatically generates slug from name. Returns existing tag if slug already exists.

get_config()

Gets the current Posts module configuration and stats.

Examples

iex> get_config()
%{enabled: true, total_posts: 42, published_posts: 30, ...}

get_group(id, opts \\ [])

Gets a single group by ID with optional preloads.

Returns nil if group not found.

get_group!(id, opts \\ [])

Gets a single group by ID with optional preloads.

Raises Ecto.NoResultsError if group not found.

get_post(id, opts \\ [])

Gets a single post by ID with optional preloads.

Returns nil if post not found.

Parameters

  • id - Post ID (UUIDv7)
  • opts - Options
    • :preload - List of associations to preload

Examples

iex> get_post("018e3c4a-...")
%Post{}

iex> get_post("018e3c4a-...", preload: [:user, :media, :tags])
%Post{user: %User{}, media: [...], tags: [...]}

iex> get_post("nonexistent")
nil

get_post!(id, opts \\ [])

Gets a single post by ID with optional preloads.

Raises Ecto.NoResultsError if post not found.

Parameters

  • id - Post ID (UUIDv7)
  • opts - Options
    • :preload - List of associations to preload

Examples

iex> get_post!("018e3c4a-...")
%Post{}

iex> get_post!("018e3c4a-...", preload: [:user, :media, :tags])
%Post{user: %User{}, media: [...], tags: [...]}

iex> get_post!("nonexistent")
** (Ecto.NoResultsError)

get_post_by_slug(slug, opts \\ [])

Gets a single post by slug.

Parameters

  • slug - Post slug (e.g., "my-first-post")
  • opts - Options
    • :preload - List of associations to preload

Examples

iex> get_post_by_slug("my-first-post")
%Post{}

iex> get_post_by_slug("nonexistent")
nil

increment_comment_count(post)

Increments the comment counter for a post.

Examples

iex> increment_comment_count(post)
{1, nil}

increment_dislike_count(post)

Increments the dislike counter for a post.

Examples

iex> increment_dislike_count(post)
{1, nil}

increment_like_count(post)

Increments the like counter for a post.

Examples

iex> increment_like_count(post)
{1, nil}

increment_view_count(post)

Increments the view counter for a post.

Examples

iex> increment_view_count(post)
{1, nil}

like_post(post_uuid, user_uuid)

User likes a post.

Creates a like record and increments the post's like counter. Returns error if user already liked the post.

list_groups(opts \\ [])

Lists all groups ordered by name.

list_post_dislikes(post_uuid, opts \\ [])

Lists all dislikes for a post.

list_post_likes(post_uuid, opts \\ [])

Lists all likes for a post.

list_post_media(post_uuid, opts \\ [])

Lists media for a post (ordered by position).

list_post_mentions(post_uuid, opts \\ [])

Lists mentioned users in a post.

list_posts(opts \\ [])

Lists posts with optional filtering and pagination.

Parameters

  • opts - Options
    • :user_uuid - Filter by user
    • :status - Filter by status (draft/public/unlisted/scheduled)
    • :type - Filter by type (post/snippet/repost)
    • :search - Search in title and content
    • :page - Page number (default: 1)
    • :per_page - Items per page (default: 20)
    • :preload - Associations to preload

Examples

iex> list_posts()
[%Post{}, ...]

iex> list_posts(status: "public", page: 1, per_page: 10)
[%Post{}, ...]

iex> list_posts(user_uuid: "018e3c4a-9f6b-7890-abcd-ef1234567890", type: "post")
[%Post{}, ...]

list_posts_by_group(group_uuid, opts \\ [])

Lists posts in a group.

list_public_posts(opts \\ [])

Lists public posts only.

Parameters

Examples

iex> list_public_posts()
[%Post{}, ...]

list_user_groups(user_uuid, opts \\ [])

Lists user's groups.

list_user_posts(user_uuid, opts \\ [])

Lists user's posts.

Parameters

  • user_uuid - User UUID (UUIDv7 string)
  • opts - See list_posts/1 for options

Examples

iex> list_user_posts("019145a1-...")
[%Post{}, ...]

on_comment_created(arg1, resource_uuid, comment)

Callback invoked by the Comments module when a comment is created on a post. Increments the post's denormalized comment_count.

on_comment_deleted(arg1, resource_uuid, comment)

Callback invoked by the Comments module when a comment is deleted from a post. Decrements the post's denormalized comment_count.

parse_hashtags(text)

Parses hashtags from text.

Extracts all hashtags (#word) from text and returns list of tag names.

post_disliked_by?(post_uuid, user_uuid)

Checks if a user has disliked a post.

post_liked_by?(post_uuid, user_uuid)

Checks if a user has liked a post.

process_scheduled_posts()

Processes scheduled posts that are ready to be published.

Finds all posts with status "scheduled" where scheduled_at <= now, and publishes them. Returns list of published posts.

Should be called periodically (e.g., via Oban job every minute).

Examples

iex> process_scheduled_posts()
{:ok, 2}

publish_post(post)

Publishes a post (makes it public).

Sets status to "public" and published_at to current time.

Examples

iex> publish_post(post)
{:ok, %Post{status: "public"}}

remove_mention_from_post(post_uuid, user_uuid)

Removes a mention from a post.

remove_post_from_group(post_uuid, group_uuid)

Removes a post from a group.

remove_tag_from_post(post_uuid, tag_uuid)

Removes a tag from a post.

reorder_groups(user_uuid, group_uuid_positions)

Reorders user's groups.

reorder_media(post_uuid, file_uuid_positions)

Reorders media in a post.

resolve_comment_resources(resource_uuids)

Resolves post titles and admin paths for a list of resource IDs.

Called by the Comments module to display resource context in the admin UI. Returns a map of resource_uuid => %{title: ..., path: ...}.

schedule_post(post, scheduled_at, attrs \\ %{}, opts \\ [])

Schedules a post for future publishing.

Updates the post status to "scheduled" and creates an entry in the scheduled jobs table for execution by the cron worker.

Parameters

  • post - Post to schedule
  • scheduled_at - DateTime to publish at (must be in future)
  • attrs - Additional attributes to update (title, content, etc.)
  • opts - Options
    • :created_by_uuid - UUID of user scheduling the post

Examples

iex> schedule_post(post, ~U[2025-12-31 09:00:00Z])
{:ok, %Post{status: "scheduled"}}

iex> schedule_post(post, ~U[2025-12-31 09:00:00Z], %{title: "New Title"})
{:ok, %Post{status: "scheduled", title: "New Title"}}

undislike_post(post_uuid, user_uuid)

User removes dislike from a post.

unlike_post(post_uuid, user_uuid)

User unlikes a post.

Deletes the like record and decrements the post's like counter. Returns error if like doesn't exist.

unschedule_post(post)

Unschedules a post, reverting it to draft status.

Cancels any pending scheduled jobs for this post.

Parameters

  • post - Post to unschedule

Examples

iex> unschedule_post(post)
{:ok, %Post{status: "draft"}}

update_group(group, attrs)

Updates a group.

update_post(post, attrs)

Updates an existing post.

Parameters

  • post - Post struct to update
  • attrs - Attributes to update

Examples

iex> update_post(post, %{title: "Updated Title"})
{:ok, %Post{}}

iex> update_post(post, %{title: ""})
{:error, %Ecto.Changeset{}}