X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Ffilter.ex;h=82b9caf9b5c8e4589ed97d395f15fda29ec3d636;hb=e49b583147748be73062acc92ea510f6f55a503a;hp=fc531f7fcdd7eef6e5821e066143bde394303424;hpb=3aa25b008d145bc7bfda907bca3b327753380728;p=akkoma diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index fc531f7fc..82b9caf9b 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -11,6 +11,9 @@ defmodule Pleroma.Filter do alias Pleroma.Repo alias Pleroma.User + @type t() :: %__MODULE__{} + @type format() :: :postgres | :re + schema "filters" do belongs_to(:user, User, type: FlakeId.Ecto.CompatType) field(:filter_id, :integer) @@ -18,15 +21,16 @@ defmodule Pleroma.Filter do field(:whole_word, :boolean, default: true) field(:phrase, :string) field(:context, {:array, :string}) - field(:expires_at, :utc_datetime) + field(:expires_at, :naive_datetime) timestamps() end + @spec get(integer() | String.t(), User.t()) :: t() | nil def get(id, %{id: user_id} = _user) do query = from( - f in Pleroma.Filter, + f in __MODULE__, where: f.filter_id == ^id, where: f.user_id == ^user_id ) @@ -34,14 +38,17 @@ defmodule Pleroma.Filter do Repo.one(query) end + @spec get_active(Ecto.Query.t() | module()) :: Ecto.Query.t() def get_active(query) do from(f in query, where: is_nil(f.expires_at) or f.expires_at > ^NaiveDateTime.utc_now()) end + @spec get_irreversible(Ecto.Query.t()) :: Ecto.Query.t() def get_irreversible(query) do from(f in query, where: f.hide) end + @spec get_filters(Ecto.Query.t() | module(), User.t()) :: [t()] def get_filters(query \\ __MODULE__, %User{id: user_id}) do query = from( @@ -53,7 +60,32 @@ defmodule Pleroma.Filter do Repo.all(query) end - def create(%Pleroma.Filter{user_id: user_id, filter_id: nil} = filter) do + @spec create(map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} + def create(attrs \\ %{}) do + Repo.transaction(fn -> create_with_expiration(attrs) end) + end + + defp create_with_expiration(attrs) do + with {:ok, filter} <- do_create(attrs), + {:ok, _} <- maybe_add_expiration_job(filter) do + filter + else + {:error, error} -> Repo.rollback(error) + end + end + + defp do_create(attrs) do + %__MODULE__{} + |> cast(attrs, [:phrase, :context, :hide, :expires_at, :whole_word, :user_id, :filter_id]) + |> maybe_add_filter_id() + |> validate_required([:phrase, :context, :user_id, :filter_id]) + |> maybe_add_expires_at(attrs) + |> Repo.insert() + end + + defp maybe_add_filter_id(%{changes: %{filter_id: _}} = changeset), do: changeset + + defp maybe_add_filter_id(%{changes: %{user_id: user_id}} = changeset) do # If filter_id wasn't given, use the max filter_id for this user plus 1. # XXX This could result in a race condition if a user tries to add two # different filters for their account from two different clients at the @@ -61,7 +93,7 @@ defmodule Pleroma.Filter do max_id_query = from( - f in Pleroma.Filter, + f in __MODULE__, where: f.user_id == ^user_id, select: max(f.filter_id) ) @@ -76,34 +108,92 @@ defmodule Pleroma.Filter do max_id + 1 end - filter - |> Map.put(:filter_id, filter_id) - |> Repo.insert() + change(changeset, filter_id: filter_id) + end + + # don't override expires_at, if passed expires_at and expires_in + defp maybe_add_expires_at(%{changes: %{expires_at: %NaiveDateTime{} = _}} = changeset, _) do + changeset end - def create(%Pleroma.Filter{} = filter) do - Repo.insert(filter) + defp maybe_add_expires_at(changeset, %{expires_in: expires_in}) + when is_integer(expires_in) and expires_in > 0 do + expires_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(expires_in) + |> NaiveDateTime.truncate(:second) + + change(changeset, expires_at: expires_at) end - def delete(%Pleroma.Filter{id: filter_key} = filter) when is_number(filter_key) do - Repo.delete(filter) + defp maybe_add_expires_at(changeset, %{expires_in: nil}) do + change(changeset, expires_at: nil) end - def delete(%Pleroma.Filter{id: filter_key} = filter) when is_nil(filter_key) do - %Pleroma.Filter{id: id} = get(filter.filter_id, %{id: filter.user_id}) + defp maybe_add_expires_at(changeset, _), do: changeset - filter - |> Map.put(:id, id) - |> Repo.delete() + defp maybe_add_expiration_job(%{expires_at: %NaiveDateTime{} = expires_at} = filter) do + Pleroma.Workers.PurgeExpiredFilter.enqueue(%{ + filter_id: filter.id, + expires_at: DateTime.from_naive!(expires_at, "Etc/UTC") + }) end - def update(%Pleroma.Filter{} = filter, params) do + defp maybe_add_expiration_job(_), do: {:ok, nil} + + @spec delete(t()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} + def delete(%__MODULE__{} = filter) do + Repo.transaction(fn -> delete_with_expiration(filter) end) + end + + defp delete_with_expiration(filter) do + with {:ok, _} <- maybe_delete_old_expiration_job(filter, nil), + {:ok, filter} <- Repo.delete(filter) do + filter + else + {:error, error} -> Repo.rollback(error) + end + end + + @spec update(t(), map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} + def update(%__MODULE__{} = filter, params) do + Repo.transaction(fn -> update_with_expiration(filter, params) end) + end + + defp update_with_expiration(filter, params) do + with {:ok, updated} <- do_update(filter, params), + {:ok, _} <- maybe_delete_old_expiration_job(filter, updated), + {:ok, _} <- + maybe_add_expiration_job(updated) do + updated + else + {:error, error} -> Repo.rollback(error) + end + end + + defp do_update(filter, params) do filter |> cast(params, [:phrase, :context, :hide, :expires_at, :whole_word]) |> validate_required([:phrase, :context]) + |> maybe_add_expires_at(params) |> Repo.update() end + defp maybe_delete_old_expiration_job(%{expires_at: nil}, _), do: {:ok, nil} + + defp maybe_delete_old_expiration_job(%{expires_at: expires_at}, %{expires_at: expires_at}) do + {:ok, nil} + end + + defp maybe_delete_old_expiration_job(%{id: id}, _) do + with %Oban.Job{} = job <- Pleroma.Workers.PurgeExpiredFilter.get_expiration(id) do + Repo.delete(job) + else + nil -> {:ok, nil} + end + end + + @spec compose_regex(User.t() | [t()], format()) :: String.t() | Regex.t() | nil def compose_regex(user_or_filters, format \\ :postgres) def compose_regex(%User{} = user, format) do