View Source Bonfire.Social.Threads (Bonfire v0.9.11-social-beta.3)

Handle mutating and querying discussion threads and replies.

Provides functionality for managing threaded discussions, including creating replies, querying threads, and handling participants.

It is the context module for Bonfire.Data.Social.Replied which contains these fields:

  • id: object
  • reply_to: what object or activity are we replying to
  • thread: what discussion thread we're in, if any (usually same as the ID of the original object that started the thread)
  • direct_replies_count: number of direct replies to this object (automatically counted and updated)
  • nested_replies_count: number of nested replies to this object and any replies to it (automatically aggregated, counted and updated)
  • total_replies_count: direct replies + nested replies (automatically summed)
  • path: breadcrumbs leading from the reply_to all the way to the original object that started the thread. Powered by EctoMaterializedPath.

Summary

Functions

Prepares a thread or reply for federation with ActivityPub.

Arranges replies into a tree structure.

Casts a changeset with reply_to and threading info.

Counts participants in a thread.

Creates a parent replied record within a changeset.

Finds the object being replied to.

Finds the thread for a reply.

Initializes a parent replied record.

Lists participants of a thread or individual object.

Lists replies in a thread.

Marks all unseen replies as seen.

re-order distinct threads after DISTINCT ON ordered them by thread_id - Note: does not support pagination

Builds a query for thread replies.

re-order distinct threads after DISTINCT ON ordered them by thread_id - Note: this results in (Ecto.QueryError) cannot preload associations in subquery in query

Reads a thread by its ID.

Counts unseen replies.

Builds a query for unseen replies.

Functions

ap_prepare(object_or_thread_or_reply_to_id, key \\ :thread_id)

Prepares a thread or reply for federation with ActivityPub.

Parameters

  • object_or_thread_or_reply_to_id: The object, thread, or reply ID
  • key: The key to use for preparation (:thread_id or :reply_to_id, default is :thread_id)

Examples

iex> ap_prepare("thread_123")
"https://example.com/ap/objects/thread_123"

arrange_replies(replies, opts \\ [])

Arranges replies.

TODOC: how is it different than arrange_replies_tree/2?

Parameters

  • replies: List of replies
  • opts: Arrangement options

Examples

iex> arrange_replies([%{id: "1"}, %{id: "2", path: ["1"]}])
%{"1" => %{id: "1", children: %{"2" => %{id: "2", path: ["1"]}}}}

arrange_replies_tree(replies, opts \\ [])

Arranges replies into a tree structure.

Powered by https://github.com/bonfire-networks/ecto_materialized_path

Parameters

  • replies: List of replies
  • opts: Arrangement options

Examples

iex> arrange_replies_tree([%{id: "1"}, %{id: "2", reply_to_id: "1"}])
%{"1" => %{id: "1", direct_replies: [%{id: "2", reply_to_id: "1"}]}}

base_query()

cast(changeset, attrs, user, preset_or_custom_boundary)

Casts a changeset with reply_to and threading info.

If it's not a reply or the user is not permitted to reply to the thing, a new thread will be created.

Parameters

  • changeset: The changeset to be updated
  • attrs: Attributes for the reply
  • user: The user creating the reply
  • _preset_or_custom_boundary: Boundary setting (currently unused)

Examples

iex> cast(changeset, %{reply_to_id: "123"}, user, nil)
%Ecto.Changeset{}

changeset(replied \\ %Replied{}, attrs)

count_participants(thread_id, opts \\ [])

Counts participants in a thread.

Parameters

  • thread_id: The ID of the thread
  • opts: Additional options, should contain current_user to check for permission

Examples

iex> count_participants("thread_123")
5

create_parent_replied(changeset, replied, replied_attrs)

Creates a parent replied record within a changeset.

Parameters

  • changeset or object: The changeset to update
  • replied: The replied struct
  • replied_attrs: Attributes for the replied record

Examples

iex> create_parent_replied(changeset, %Replied{}, %{id: "789", thread_id: "456"})
%Ecto.Changeset{}

filter(arg1, thread_id, query)

Group per-thread

find_reply_to(attrs, user)

Finds the object being replied to.

Parameters

  • attrs: Attributes containing reply information
  • user: The user attempting to reply

Returns

  • {:ok, reply} if the reply object is found and the user has permission
  • {:error, reason} otherwise, where reason may be :not_found or :not_permitted

Examples

iex> find_reply_to(%{reply_to_id: "123"}, user)
{:ok, %{id: "123", ...}}

find_thread(attrs, user)

Finds the thread for a reply.

Parameters

  • attrs: Attributes containing thread information
  • user: The user attempting to access the thread

Examples

iex> find_thread(%{thread_id: "456"}, user)
{:ok, %{id: "456", ...}}

init_parent_replied(replied_attrs)

Initializes a parent replied record.

Parameters

  • replied_attrs: Attributes for the replied record

Examples

iex> init_parent_replied(%{id: "789", thread_id: "456"})
{:ok, %Replied{}}

list_participants(activity_or_object, thread_or_object_id \\ nil, opts \\ [])

Lists participants of a thread or individual object.

Parameters

  • activity_or_object: The activity or object to list participants for
  • thread_or_object_id: Optional thread or object ID
  • opts: Additional options

Examples

iex> list_participants(activity, "thread_123", limit: 10)
[%{id: "user1", ...}, %{id: "user2", ...}]

list_replies(thread, opts \\ [])

Lists replies in a thread.

Parameters

  • thread: The thread or thread ID
  • opts: Additional options

Examples

iex> list_replies("thread_123", limit: 10)
%{edges: [%{id: "reply1", ...}, %{id: "reply2", ...}]}

mark_all_seen(filters, opts)

Marks all unseen replies as seen.

Parameters

  • filters: Filter criteria
  • opts: Additional options

Examples

iex> mark_all_seen([thread_id: "123"], current_user: user)
{:ok, [%{id: "reply1"}, %{id: "reply2"}]}

maybe_re_order_result(result, opts)

re-order distinct threads after DISTINCT ON ordered them by thread_id - Note: does not support pagination

maybe_with_pins(query, thread_id, opts)

query(filters, opts)

Builds a query for thread replies.

Parameters

  • filter: Filter criteria (e.g., [thread_id: "123"])
  • opts: Additional query options

Examples

iex> query([thread_id: "123"], preload: [:posts])
%Ecto.Query{}

query_module()

Callback implementation for Bonfire.Common.QueryModule.query_module/0.

re_order_using_subquery(query, opts)

re-order distinct threads after DISTINCT ON ordered them by thread_id - Note: this results in (Ecto.QueryError) cannot preload associations in subquery in query

read(object_id, opts)

Reads a thread by its ID.

Parameters

  • object_id: The ID of the object to read
  • opts: should contain current_user to check for read permissions

Returns

  • {:ok, object} if the object is found and readable
  • {:error, reason} otherwise

Examples

iex> read("123", current_user: me)
{:ok, %{id: "123", ...}}

schema_module()

Callback implementation for Bonfire.Common.QueryModule.schema_module/0.

unseen_count(filters, opts)

Counts unseen replies.

Parameters

  • filters: Filter criteria
  • opts: Additional options

Examples

iex> unseen_count([thread_id: "123"], current_user: user)
5

unseen_query(filters, opts)

Builds a query for unseen replies.

Parameters

  • filters: Filter criteria
  • opts: Additional query options

Returns

  • {:ok, query} if the query can be built
  • {:error, reason} otherwise

Examples

iex> unseen_query([thread_id: "123"], current_user: user)
{:ok, %Ecto.Query{}}