View Source Bonfire.Social.FeedLoader (Bonfire v0.9.11-social-beta.6)

Determines the appropriate filters, joins, and/or preloads for feed queries based.

Entrypoint for Bonfire.Social.Feeds and Bonfire.Social.FeedActivities, and Bonfire.Social.Activities.

Summary

Functions

Returns the count of items in a feed based on given filters and options.

Returns the count of distinct subjects in a feed based on given filters and options.

Gets a feed based on filters and options.

Gets feed ids and options for the given feed or list of feeds.

Returns paginated results for the given query.

Returns a page of feed activities (reverse chronological) + pagination metadata

Maps high-level preload keys to their corresponding detailed preload lists.

Match feed filters against rule criteria.

Gets a user's home feed, a combination of all feeds the user is subscribed to.

Parameterizes the filters by replacing parameterized values with values from opts.

Computes the list of preloads to apply based on the provided filters. Returns a list of preload atoms.

Converts socket, assigns, or options to feed options.

Gets an aliased feed's filters by name, with optional parameters.

Return a boundarised query for a feed

add assocs needed in timelines/feeds

add assocs needed in lists of objects

Replaces parameters in the filter value with the actual values from opts.

Functions

contextual_preloads_from_filters(feed_filters, context, context_rules \\ preloads_by_context_rules())

count(filters \\ [], opts \\ [])

Returns the count of items in a feed based on given filters and options.

Examples

> count(filters, current_user: me)
10

count_subjects(filters \\ [], opts \\ [])

Returns the count of distinct subjects in a feed based on given filters and options.

Examples

> count_subjects(filters, opts)
3

default_feed_name(opts)

feed(name_or_filters \\ nil, opts \\ [])

@spec feed(map() | atom() | String.t(), Keyword.t()) :: map()

feed(feed_name, filters, opts)

Gets a feed based on filters and options.

Parameters

  • name_or_filters - A map of filter parameters (see FeedFilters for the list of supported filters) or a feed name atom/string if no other filters are needed
  • opts - Options that aren't filter-related

Examples

iex> %{edges: _, page_info: %Paginator.PageInfo{}} = Bonfire.Social.FeedActivities.feed(:explore)

iex> %{edges: _, page_info: %Paginator.PageInfo{}} = Bonfire.Social.FeedActivities.feed(%{feed_name: :explore})

> Bonfire.Social.FeedActivities.feed("feed123", [])
%{edges: [%{activity: %{}}], page_info: %Paginator.PageInfo{}}

feed_contains?(feed_name, object, opts \\ [])

feed_contains_single?(feed_name, filters, opts)

feed_filtered(feed_name, filters, opts)

feed_ids_and_opts(feed_name, opts)

Gets feed ids and options for the given feed or list of feeds.

TODO: this should be replaced by feed presets

Examples

> feed_ids_and_opts(feed_name, opts)
{feed_ids, opts}

> feed_ids_and_opts({feed_name, feed_id}, opts)

> feed_ids_and_opts(:my, [current_user: me])
{["feed_id1", "feed_id2"], [exclude_activity_types: [:flag, :boost, :follow]]}

> feed_ids_and_opts({:notifications, "feed_id3"}, [current_user: me])
{"feed_id3", [include_flags: true, exclude_activity_types: false, show_objects_only_once: false, preload: [:notifications]]}

feed_many_paginated(query, filters, opts)

Returns paginated results for the given query.

Examples

> feed_many_paginated(query, opts)
%{edges: edges, page_info: page_info}

feed_name_or_default(name, opts)

feed_paginated(filters \\ %{}, opts \\ [])

Returns a page of feed activities (reverse chronological) + pagination metadata

TODO: consolidate with feed/2?

Examples

iex> %{edges: _, page_info: %{}} = feed_paginated([], [])

iex> query = Ecto.Query.from(f in Bonfire.Data.Social.FeedPublish)
iex> %{edges: _, page_info: %{}} = feed_paginated([], base_query: query)

feed_with_object(feed_name, object, opts \\ [])

filter_already_preloaded(preloads, already_preloaded)

map_activity_preloads(preloads, already_preloaded \\ [], preload_presets \\ preload_presets())

Maps high-level preload keys to their corresponding detailed preload lists.

Examples

# Single preload key
iex> map_activity_preloads([:feed]) |> Enum.sort()
[
  :with_creator,
  :with_media,
  :with_object_more,
  :with_replied,
  :with_subject
]

# Multiple preload keys
iex> map_activity_preloads([:feed, :notifications]) |> Enum.sort()
[:notifications, :with_creator, :with_media, :with_object_more, :with_replied, :with_subject]

# With :all key it includes all defined preloads
iex> map_activity_preloads([:all]) |> Enum.sort()
[
  :maybe_with_labelled,
  :tags,
  :with_creator,
  :with_media,
  :with_object_more,
  :with_parent,
  :with_post_content,
  :with_replied,
  :with_reply_to,
  :with_seen,
  :with_subject,
  :with_thread_name,
  :with_verb
]

# With unknown key
iex> map_activity_preloads([:unknown_key])
[:unknown_key]

# Empty list returns empty list
iex> map_activity_preloads([])
[]

# Removes duplicates when preload lists overlap
iex> map_activity_preloads([:posts, :posts_with_thread]) |> Enum.sort()
[
  :with_post_content,
  :with_replied,
  :with_subject,
  :with_thread_name
]

matches_filter?(rule_match_criteria, feed_filters)

Match feed filters against rule criteria.

Examples

iex> matches_filter?(%{types: "*"}, %{types: "post"})
true

iex> matches_filter?(%{types: ["post", "comment"]}, %{types: ["comment", "reaction"]})
true

iex> matches_filter?(%{types: "post"}, %{types: ["comment", "post"]})
true

iex> matches_filter?(%{types: :post}, %{types: ["comment", "post"]})
true

iex> matches_filter?(%{types: "post"}, %{types: [:comment, :post]})
true

iex> matches_filter?(%{types: ["post"]}, %{types: "post"})
true

iex> matches_filter?(%{types: "post"}, %{types: "comment"})
false

iex> matches_filter?(%{types: :post}, %{types: "post"})
true

my_feed(opts, home_feed_ids \\ nil)

Gets a user's home feed, a combination of all feeds the user is subscribed to.

TODO: should just be an alias to feed(:my, opts)

Examples

> Bonfire.Social.FeedActivities.my_feed([current_user: %{id: "user123"}])
%{edges: [%{activity: %{}}], page_info: %{}}

> Bonfire.Social.FeedActivities.my_feed([current_user: %{id: "user123"}], ["feed_id1", "feed_id2"])
%{edges: [%{activity: %{}}], page_info: %{}}

parameterize_filters(filters, parameters, opts)

Parameterizes the filters by replacing parameterized values with values from opts.

Examples

# 1: Parameterizing a simple filter
iex> parameterize_filters(%{}, %{subjects: [:me]}, current_user: %{id: "alice"})
%{subjects: [%{id: "alice"}]}

# 2: Parameterizing multiple filters
iex> parameterize_filters(%{}, %{subjects: [:me], tags: [:hashtag]}, current_user: %{id: "alice"}, hashtag: "elixir")
%{subjects: [%{id: "alice"}], tags: ["elixir"]}

# 3: Parameterizing with undefined options
iex> parameterize_filters(%{}, %{subjects: :me}, current_user: nil)
%{subjects: nil}

# 4: Handling filters that don't require parameterization
iex> parameterize_filters(%{activity_types: ["like"]}, %{}, current_user: "bob")
%{activity_types: ["like"]}

preload_presets()

preloads_by_context_rules()

preloads_from_filters(feed_filters, filter_rules \\ preloads_from_filters_rules())

Computes the list of preloads to apply based on the provided filters. Returns a list of preload atoms.

Uses rules defined in configuration rather than code.

Multiple rules can match and their preloads will be merged, with exclusions applied last.

Examples

iex> filters = %{feed_name: "remote"}
iex> preloads_from_filters(filters) |> Enum.sort()
[:with_creator, :with_media, :with_object_more, :with_peered, :with_reply_to, :with_subject]

iex> filters = %{feed_name: :remote}
iex> preloads_from_filters(filters) |> Enum.sort()
[:with_creator, :with_media, :with_object_more, :with_peered, :with_reply_to, :with_subject]

iex> filters = %{feed_name: ["remote"]}
iex> preloads_from_filters(filters) |> Enum.sort()
[:with_creator, :with_media, :with_object_more, :with_peered, :with_reply_to, :with_subject]

iex> filters = %{feed_name: [:remote]}
iex> preloads_from_filters(filters) |> Enum.sort()
[:with_creator, :with_media, :with_object_more, :with_peered, :with_reply_to, :with_subject]

iex> filters = %{subjects: ["alice"]}
iex> preloads_from_filters(filters) |> Enum.sort()
[:with_creator, :with_media, :with_object_more, :with_reply_to]

iex> filters = %{feed_name: "unknown"}
iex> preloads_from_filters(filters) |> Enum.sort()
[
  :with_creator,
  :with_media,
  :with_object_more,
  :with_peered,
  :with_reply_to,
  :with_subject
]

preloads_from_filters_rules()

prepare_filters_and_opts(filters, opts)

Converts socket, assigns, or options to feed options.

Examples

> assigns = %{exclude_activity_types: [:flag, :boost]}
> to_feed_options(filters, assigns)
[exclude_activity_types: [:flag, :boost, :follow]]

preset_feed_filters(name, opts \\ [])

@spec preset_feed_filters(String.t(), map()) :: {:ok, map()} | {:error, atom()}

Gets an aliased feed's filters by name, with optional parameters.

Examples

# 1: Retrieve a preset feed without parameters
iex> {:ok, %{feed_name: :local, exclude_activity_types: [:like]}} = preset_feed_filters(:local, [])

# 1: Retrieve a preset feed without parameters
iex> {:ok, %{feed_name: :local, exclude_activity_types: [:like]}} =preset_feed_filters(:local, [])

# 2: Retrieve a preset feed with parameters
iex> {:ok, %{subjects: "alice"}} = preset_feed_filters(:user_activities, [by: "alice"])

# 3: Feed not found (error case)
iex> preset_feed_filters("unknown_feed", [])
{:error, :not_found}

# 4: Preset feed with parameterized filters
iex> {:ok, %{activity_types: :like, subjects: %{id: "alice"}}} = preset_feed_filters(:liked_by_me, current_user: %{id: "alice"})

# 5: Feed with `current_user_required` should check for current user
iex> {:ok, %{feed_name: :messages}} = preset_feed_filters(:messages, current_user: %{id: "alice"})

# 6: Feed with `current_user_required` and no current user
iex> preset_feed_filters(:messages, [])
** (Bonfire.Fail.Auth) You need to log in first.

# 7: Custom feed with additional parameters
iex> {:ok, %{activity_types: :follow, objects: "alice"}} = preset_feed_filters(:user_followers, [by: "alice"])

query(filters \\ [], opts \\ [], query \\ default_query())

Return a boundarised query for a feed

query_extras_boundarised(query \\ nil, filters, opts)

add assocs needed in timelines/feeds

query_object_extras_boundarised(query \\ nil, filters, opts)

add assocs needed in lists of objects

replace_parameters(value, filters, opts)

Replaces parameters in the filter value with the actual values from opts.

Examples

# Replacing a `me` parameter with the current user
iex> replace_parameters(:me, %{}, current_user: %{id: "alice"})
%{id: "alice"}

# Replacing a `:current_user` parameter with the current user only if available
iex> replace_parameters(:current_user, %{}, current_user: nil)
nil

# Replacing a `by` parameter with the a value from the filters
iex> replace_parameters(:by, %{by: %{id: "alice"}}, [])
%{id: "alice"}

# Replacing a `by` parameter with the a value from the opts
iex> replace_parameters(:by, %{}, by: %{id: "alice"})
%{id: "alice"}

# Replacing a `:by` parameter with the current user as a fallback
iex> replace_parameters(:by, %{}, current_user: %{id: "alice"})
%{id: "alice"}

# Failing with `:current_user_required` parameter if we have no current user
iex> replace_parameters(:current_user_required, %{}, current_user: nil)
** (Bonfire.Fail.Auth) You need to log in first.

# Handling a parameter that is in the opts
iex> replace_parameters(:type, %{}, type: "post")
"post"

# Handling a parameter that is in the filters
iex> replace_parameters(:type, %{type: "post"}, [])
"post"

# Handling a parameter that is in the filters with string key
iex> replace_parameters(:type, %{"type"=> "post"}, [])
"post"

# # Handling a string key parameter that is in the filters
# iex> replace_parameters("type", %{type: "post"}, [])
# "post"

# # Handling a string key parameter that is in the opts - FIXME
# iex> replace_parameters("type", %{}, type: "post")
# "post"

# Handling a parameter that is not in the opts
iex> replace_parameters(:unknown, %{}, current_user: "bob")
:unknown

skip_types_default()

skip_verbs_default()