63 lines
1.6 KiB
Elixir
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
|