View Source Bonfire.Common.Utils (Bonfire v0.9.10-classic-beta.169)

Various very commonly used utility functions for the Bonfire application.

This module should contain only a few generic and/or heavily-used functions, and any other functions should be in more specific modules (or in other extensions altogether) for e.g.:

We may also want to consider reusing functions from existing utils libraries when possible and contributing missing ones there, for example:

Summary

Functions

Runs a function asynchronously in a Task. Simply a shorthand for calling functions in Task and Task.Supervisor but with support for multi-tenancy in the spawned process.

Runs a function asynchronously using Task.Supervisor. This is similar to apply_task/3 but specifically uses Task.Supervisor for supervision.

Returns the current account from socket, assigns, or options.

Returns a list of current account IDs and/or user IDs.

(Re)authenticates the current account using the provided password.

Returns the current account ID from socket, assigns, or options.

Returns the current user from socket, assigns, or options.

(Re)authenticates the current user using the provided password.

Returns the current user ID from socket, assigns, or options.

Ensures that the current user is present and raises an exception if not logged in.

Checks if the given value is nil, an empty enumerable, or an empty string.

Applies the given function if the first parameter is not nil.

Helper for calling hypothetical functions another modules.

Returns the value of a key from options keyword list or map, or a fallback if not present or empty.

Checks if the given value is nil, false, 0, or an empty value (using empty?/1).

Unwraps an {:ok, val} tuple, returning the value. If not OK, returns a fallback value (default is nil).

Rounds a number and uses Bonfire.Common.Localise.Cldr.Number.to_string/2 function to format into a human readable string.

Rounds a number to the nearest specified target.

Converts a map, user, socket, tuple, etc, to a keyword list for standardised use as function options.

Functions

Link to this function

apply_error(error, args, opts)

View Source
Link to this function

apply_task(function \\ :async, fun, opts \\ [])

View Source

Runs a function asynchronously in a Task. Simply a shorthand for calling functions in Task and Task.Supervisor but with support for multi-tenancy in the spawned process.

  • Task.async/1 the caller creates a new process links and monitors it. Once the task action finishes, a message is sent to the caller with the result. Task.await/2 is used to read the message sent by the task. When using async, you must await a reply as they are always sent.

  • Task.start_link/1 is suggested instead if you are not expecting a reply. It starts a statically supervised task as part of a supervision tree, linked to the calling process (meaning it will be stopped when the caller stops).

  • Task.start/1 can be used for fire-and-forget tasks, like side-effects, when you have no interest on its results nor if it completes successfully (because if the server is shut down it won't be restarted).

For more serious tasks, consider using Oban or apply_task_supervised/3 for supervised tasks when possible:

Parameters

  • function: The type of task to start (e.g. :async, :start_link, or :start).
  • fun: The function to execute async.
  • opts: Options for task execution, including:
    • :module - The module to use for task execution (defaults to Task).

Examples

> apply_task(:async, fn -> IO.puts("Async task") end)
# Output: "Async task"

> {apply_task(:start, fn -> IO.puts("Fire-and-forget task") end)
# Output: "Fire-and-forget task"

> apply_task(:start_link, fn -> IO.puts("Supervised task") end)
# Output: "Supervised task"
Link to this function

apply_task_supervised(supervisor, fun, opts \\ [])

View Source

Runs a function asynchronously using Task.Supervisor. This is similar to apply_task/3 but specifically uses Task.Supervisor for supervision.

Parameters

  • module: The supervisor module to use for task execution
  • fun: The function to execute async
  • opts: Options for task execution, including:
    • :function - The Task.Supervisor function to use for task execution (defaults to :async).

Examples

> apply_task_supervised(MySupervisor, fn -> IO.puts("Supervised async task") end)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
# because `MySupervisor` is not defined and/or started ^
Link to this function

current_account(current_account_or_socket_or_opts, recursing \\ false)

View Source

Returns the current account from socket, assigns, or options.

This function traverses various possible structures to find and return the current account.

Examples

iex> Bonfire.Common.Utils.current_account(%{current_account: %{id: "account1"}})
%{id: "account1"}

iex> Bonfire.Common.Utils.current_account(%{assigns: %{current_account: %{id: "account2"}}})
%{id: "account2"}

iex> Bonfire.Common.Utils.current_account(%{socket: %{assigns: %{current_account: %{id: "account3"}}}})
%{id: "account3"}

iex> Bonfire.Common.Utils.current_account([current_account: %{id: "account4"}])
%{id: "account4"}
Link to this function

current_account_and_or_user_ids(assigns)

View Source

Returns a list of current account IDs and/or user IDs.

This function returns a keyword list with the current account IDs and/or user IDs.

Examples

iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS", current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
[account: "2CC0VNTSARE1S01AT10NGR0VPS", user: "5EVSER1S0STENS1B1YHVMAN01D"]

iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account: %{id: "2CC0VNTSARE1S01AT10NGR0VPS"}, current_user: %{id: "5EVSER1S0STENS1B1YHVMAN01D"}})
[account: "2CC0VNTSARE1S01AT10NGR0VPS", user: "5EVSER1S0STENS1B1YHVMAN01D"]

iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"})
[account: "2CC0VNTSARE1S01AT10NGR0VPS"]

iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
[user: "5EVSER1S0STENS1B1YHVMAN01D"]

iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{})
[]
Link to this function

current_account_auth!(context, password)

View Source

(Re)authenticates the current account using the provided password.

Raises an exception if the credentials are invalid.

Examples

> Bonfire.Common.Utils.current_account_auth!(%{current_account: %{id: "2CC0VNTSARE1S01AT10NGR0VPS"}}, "wrong-password")
** (Bonfire.Fail.Auth) We couldn't find an account with the details you provided.
Link to this function

current_account_id(current_account_or_socket_or_opts, recursing \\ false)

View Source

Returns the current account ID from socket, assigns, or options.

This function traverses various possible structures to find and return the current account ID.

Examples

iex> Bonfire.Common.Utils.current_account_id(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"})
"2CC0VNTSARE1S01AT10NGR0VPS"

iex> Bonfire.Common.Utils.current_account_id(%{assigns: %{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"}})
"2CC0VNTSARE1S01AT10NGR0VPS"

iex> Bonfire.Common.Utils.current_account_id(%{socket: %{assigns: %{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"}}})
"2CC0VNTSARE1S01AT10NGR0VPS"

iex> Bonfire.Common.Utils.current_account_id("2CC0VNTSARE1S01AT10NGR0VPS")
"2CC0VNTSARE1S01AT10NGR0VPS"
Link to this function

current_user(current_user_or_socket_or_opts, recursing \\ false)

View Source

Returns the current user from socket, assigns, or options.

This function traverses various possible structures to find and return the current user (or current user ID if that's all that's available).

Examples

iex> Bonfire.Common.Utils.current_user(%{current_user: %{id: "user1"}})
%{id: "user1"}

iex> Bonfire.Common.Utils.current_user(%{assigns: %{current_user: %{id: "user2"}}})
%{id: "user2"}

iex> Bonfire.Common.Utils.current_user(%{socket: %{assigns: %{current_user: %{id: "user3"}}}})
%{id: "user3"}

iex> Bonfire.Common.Utils.current_user([current_user: %{id: "user4"}])
%{id: "user4"}

iex> Bonfire.Common.Utils.current_user(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
"5EVSER1S0STENS1B1YHVMAN01D"
Link to this function

current_user_auth!(context, password)

View Source

(Re)authenticates the current user using the provided password.

Raises an exception if the credentials are invalid.

Examples

> Bonfire.Common.Utils.current_user_auth!(%{current_user: %{id: "user1"}}, "password123")
** (Bonfire.Fail.Auth) We couldn't find an account with the details you provided. 
Link to this function

current_user_id(current_user_or_socket_or_opts, recursing \\ false)

View Source

Returns the current user ID from socket, assigns, or options.

This function traverses various possible structures to find and return the current user ID.

Examples

iex> Bonfire.Common.Utils.current_user_id(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
"5EVSER1S0STENS1B1YHVMAN01D"

iex> Bonfire.Common.Utils.current_user_id(%{assigns: %{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"}})
"5EVSER1S0STENS1B1YHVMAN01D"

iex> Bonfire.Common.Utils.current_user_id(%{assigns: %{__context__: %{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"}}})
"5EVSER1S0STENS1B1YHVMAN01D"

iex> Bonfire.Common.Utils.current_user_id("5EVSER1S0STENS1B1YHVMAN01D")
"5EVSER1S0STENS1B1YHVMAN01D"

iex> Bonfire.Common.Utils.current_user_id("invalid id")
nil
Link to this function

current_user_required!(context)

View Source

Ensures that the current user is present and raises an exception if not logged in.

Examples

iex> Bonfire.Common.Utils.current_user_required!(%{current_user: %{id: "user1"}})
%{id: "user1"}

> Bonfire.Common.Utils.current_user_required!(%{})
** (Bonfire.Fail.Auth) You need to log in first. 

Callback implementation for Bonfire.Common.ExtensionModule.declared_extension/0.

Checks if the given value is nil, an empty enumerable, or an empty string.

Parameters

  • v: The value to check.

Examples

iex> empty?(nil)
true

iex> empty?("")
true

iex> empty?([])
true

iex> empty?([1, 2, 3])
false

iex> empty?("hello")
false

Applies the given function if the first parameter is not nil.

Parameters

  • val: The value to check.
  • change_fn: A function to apply if val is not nil.

Examples

iex> maybe(nil, fn x -> x * 2 end)
nil

iex> maybe(3, fn x -> x * 2 end)
6
Link to this function

maybe_apply(module, fun, args \\ [], opts \\ [])

View Source

Helper for calling hypothetical functions another modules.

Attempts to apply a function from a specified module with the given arguments and returns the result.

Returns an error if the function is not defined, unless a fallback function was provided to be invoked, or a fallback value to be returned.

Parameters

  • module: The module to check for the function.
  • funs: A list of function names (atoms) to try.
  • args: Arguments to pass to the function.
  • opts: Options for error handling and fallback. Options include:
    • :fallback_fun - A function to call if the primary function is not found.
    • :fallback_return - A default return value if the function cannot be applied.

Examples

iex> maybe_apply(Enum, :map, [[1, 2, 3], &(&1 * 2)])
[2, 4, 6]

iex> maybe_apply(Enum, [:nonexistent_fun], [])
{:error, "None of the functions [:nonexistent_fun] are defined at Elixir.Enum with arity 0"}

iex> maybe_apply(Enum, [:nonexistent_fun], [], fallback_fun: fn error, _args, _opts -> raise "Failed" end)
** (RuntimeError) Failed

iex> maybe_apply(SomeModule, [:some_fun], [1, 2, 3], fallback_return: "Failed")
# Output: [warning] maybe_apply: No such module (Elixir.SomeModule) could be loaded. - with args: ([1, 2, 3])
"Failed"
Link to this function

maybe_apply_fallback(error, args, opts)

View Source
Link to this function

maybe_from_opts(opts, key, fallback \\ nil)

View Source

Returns the value of a key from options keyword list or map, or a fallback if not present or empty.

Checks if the given value is nil, false, 0, or an empty value (using empty?/1).

Parameters

  • v: The value to check.

Examples

iex> nothing?(nil)
true

iex> nothing?(false)
true

iex> nothing?(0)
true

iex> nothing?("")
true

iex> nothing?([1, 2, 3])
false

iex> nothing?("hello")
false
Link to this function

ok_unwrap(val, fallback \\ nil)

View Source

Unwraps an {:ok, val} tuple, returning the value. If not OK, returns a fallback value (default is nil).

Parameters

  • val: The value or tuple to unwrap.
  • fallback: The fallback value if the tuple is an error.

Examples

iex> ok_unwrap({:ok, 42})
42

iex> ok_unwrap({:error, "something went wrong"}, "default")
"default"

iex> ok_unwrap(:error, "default")
"default"

iex> ok_unwrap(nil, "default")
"default"

Rounds a number and uses Bonfire.Common.Localise.Cldr.Number.to_string/2 function to format into a human readable string.

Examples

iex> round_nearest(1234)
"1K"

iex> round_nearest(1600000)
"2M"
Link to this function

round_nearest(num, target)

View Source

Rounds a number to the nearest specified target.

Parameters

  • num: The number to round.
  • target: The target to round to (optional).

Examples

iex> round_nearest(1234, 10)
1230

iex> round_nearest(1234, 100)
1200

iex> round_nearest(1234, 1000)
1000
Link to this function

to_options(user_or_socket_or_opts)

View Source

Converts a map, user, socket, tuple, etc, to a keyword list for standardised use as function options.