View Source Bonfire.Social.Threads (Bonfire v0.9.10-classic-beta.156)

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

Link to this function

ap_prepare(object_or_thread_or_reply_to_id, key \\ :thread_id)

View Source

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"
Link to this function

arrange_replies(replies, opts \\ [])

View Source

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"]}}}}
Link to this function

arrange_replies_tree(replies, opts \\ [])

View Source

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"}]}}
Link to this function

cast(changeset, attrs, user, preset_or_custom_boundary)

View Source

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{}
Link to this function

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

View Source
Link to this function

count_participants(thread_id, opts \\ [])

View Source

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
Link to this function

create_parent_replied(changeset, replied, replied_attrs)

View Source

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{}
Link to this function

filter(arg1, thread_id, query)

View Source

Group per-thread

Link to this function

find_reply_to(attrs, user)

View Source

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", ...}}
Link to this function

find_thread(attrs, user)

View Source

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", ...}}
Link to this function

init_parent_replied(replied_attrs)

View Source

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{}}
Link to this function

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

View Source

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", ...}]
Link to this function

list_replies(thread, opts \\ [])

View Source

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", ...}]}
Link to this function

mark_all_seen(filters, opts)

View Source

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"}]}
Link to this function

maybe_re_order_result(result, opts)

View Source

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

Link to this function

maybe_with_pins(query, thread_id, opts)

View Source

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{}

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

Link to this function

re_order_using_subquery(query, opts)

View Source

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.

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", ...}}

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

Link to this function

unseen_count(filters, opts)

View Source

Counts unseen replies.

Parameters

  • filters: Filter criteria
  • opts: Additional options

Examples

iex> unseen_count([thread_id: "123"], current_user: user)
5
Link to this function

unseen_query(filters, opts)

View Source

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{}}