frenzy/lib/frenzy/pipeline/filter_stage.ex

63 lines
1.6 KiB
Elixir

defmodule Frenzy.Pipeline.FilterStage do
require Logger
alias Frenzy.Pipeline.Stage
@behaviour Stage
@impl Stage
def apply(%{"mode" => mode, "score" => score, "rules" => rules}, item_params)
when is_binary(mode) and is_integer(score) and is_list(rules) do
item_score =
rules
|> Enum.map(fn rule -> test(rule, item_params) end)
|> Enum.sum()
matches = item_score >= score
case {mode, matches} do
{"accept", true} ->
{:ok, item_params}
{"reject", false} ->
{:ok, item_params}
_ ->
Logger.debug("Skipping item #{item_params.url} due to feed filter")
:tombstone
end
end
@impl Stage
def apply(opts, item_params) do
Logger.warn("Received invalid filter opts: #{opts}")
{:ok, item_params}
end
defp test(
%{"mode" => mode, "property" => property, "param" => param, "weight" => weight},
item_params
) do
with prop_value <- get_property(item_params, property),
true <- is_binary(prop_value),
true <- matches(prop_value, mode, param) do
weight
else
_ ->
0
end
end
def matches(value, "contains_string", param) do
String.contains?(value, param)
end
def matches(value, "matches_regex", param) do
regex = Regex.compile(param)
String.match?(value, regex)
end
defp get_property(item_params, "url"), do: item_params.url
defp get_property(item_params, "title"), do: item_params.title
defp get_property(item_params, "author"), do: item_params.author
defp get_property(_item_params, _property), do: {:error, "invalid property"}
end