diff --git a/lib/vonbraun/ecto/schema/actor.ex b/lib/vonbraun/ecto/schema/actor.ex index 7723787..954b3d3 100644 --- a/lib/vonbraun/ecto/schema/actor.ex +++ b/lib/vonbraun/ecto/schema/actor.ex @@ -18,9 +18,9 @@ defmodule Vonbraun.Ecto.Schema.Actor do @type t :: %__MODULE__{ muted: boolean(), blocked: DateTime.t(), - follows_me_state: String.t(), + follows_me_state: String.t() | nil, follows_me_ts: DateTime.t(), - following_state: String.t(), + following_state: String.t() | nil, following_ts: String.t() } @@ -92,4 +92,38 @@ defmodule Vonbraun.Ecto.Schema.Actor do end end end + + @spec mark_pending_follow(String.t(), nil | String.t(), keyword()) :: + {:ok, __MODULE__.t()} | {:error, any()} + @spec mark_pending_follow(String.t(), nil | String.t()) :: + {:error, any()} | {:ok, __MODULE__.t()} + def mark_pending_follow(id, new_state, options \\ []) + when is_binary(id) and new_state in [nil, "accepted", "pending", "rejected"] do + with {:actor, + {:ok, actor = %{:blocked => blocked?, :following_state => existing_following_state}}} <- + {:actor, maybe_insert(id)} do + valid_set_pending? = existing_following_state == nil && new_state == "pending" + + valid_set_response? = + existing_following_state == "pending" && new_state in ["accepted", "pending"] + + force? = Keyword.get(options, :force, false) + + cond do + # You NEED to unblock manually first. + blocked? -> + {:error, :blocked} + + force? || valid_set_pending? || valid_set_response? -> + changeset(actor, %{following_state: new_state, following_ts: DateTime.now!("Etc/UTC")}) + |> Repo.update() + + true -> + {:error, :invalid_state} + end + else + {:actor, {:error, error}} -> + {:error, error} + end + end end