| defmodule Plausible.Shield.IPRuleCache do |
| @moduledoc """ |
| Allows retrieving IP Rules by domain and IP |
| """ |
| alias Plausible.Shield.IPRule |
|
|
| import Ecto.Query |
| use Plausible.Cache |
|
|
| @cache_name :ip_blocklist_by_domain |
|
|
| @cached_schema_fields ~w( |
| id |
| inet |
| action |
| )a |
|
|
| @impl true |
| def name(), do: @cache_name |
|
|
| @impl true |
| def child_id(), do: :cache_ip_blocklist |
|
|
| @impl true |
| def count_all() do |
| Plausible.Repo.aggregate(IPRule, :count) |
| end |
|
|
| @impl true |
| def base_db_query() do |
| from rule in IPRule, |
| inner_join: s in assoc(rule, :site), |
| select: { |
| s.domain, |
| s.domain_changed_from, |
| %{struct(rule, ^@cached_schema_fields) | from_cache?: true} |
| } |
| end |
|
|
| @impl true |
| def get_from_source({domain, address}) do |
| query = |
| base_db_query() |
| |> where([rule, site], rule.inet == ^address and site.domain == ^domain) |
|
|
| case Plausible.Repo.one(query) do |
| {_, _, rule = %IPRule{}} -> %IPRule{rule | from_cache?: false} |
| _any -> nil |
| end |
| end |
|
|
| @impl true |
| def unwrap_cache_keys(items) do |
| Enum.reduce(items, [], fn |
| {domain, nil, object}, acc -> |
| [{{domain, to_string(object.inet)}, object} | acc] |
|
|
| {domain, domain_changed_from, object}, acc -> |
| [ |
| {{domain, to_string(object.inet)}, object}, |
| {{domain_changed_from, to_string(object.inet)}, object} | acc |
| ] |
| end) |
| end |
| end |
|
|