Add pipeline stage option validation/error reporting
This commit is contained in:
parent
d0c6831d45
commit
17310911ce
|
@ -32,6 +32,72 @@ defmodule Frenzy.Pipeline.FilterStage do
|
|||
{:ok, item_params}
|
||||
end
|
||||
|
||||
@impl Stage
|
||||
def validate_opts(opts) when is_map(opts) do
|
||||
cond do
|
||||
not (Map.has_key?(opts, "mode") and is_binary(opts["mode"]) and
|
||||
opts["mode"] in ["accept", "reject"]) ->
|
||||
{:error, "mode must be a string, either 'accept' or 'reject'"}
|
||||
|
||||
not (Map.has_key?(opts, "score") and is_integer(opts["score"])) ->
|
||||
{:error, "score must be an integer"}
|
||||
|
||||
not (Map.has_key?(opts, "rules") and is_list(opts["rules"])) ->
|
||||
{:error, "rules must be a list of rules"}
|
||||
|
||||
true ->
|
||||
validate_rules(opts)
|
||||
end
|
||||
end
|
||||
|
||||
@impl Stage
|
||||
def validate_opts(_opts), do: {:error, "options must be a map"}
|
||||
|
||||
defp validate_rules(%{"rules" => rules} = opts) do
|
||||
rules
|
||||
|> Enum.with_index()
|
||||
|> Enum.reduce_while(:ok, fn {rule, index}, :ok ->
|
||||
case validate_rule(rule) do
|
||||
:ok ->
|
||||
{:cont, :ok}
|
||||
|
||||
{:error, reason} ->
|
||||
{:halt, {:error, "invalid rule #{index}: #{reason}"}}
|
||||
end
|
||||
end)
|
||||
|> case do
|
||||
:ok ->
|
||||
{:ok, opts}
|
||||
|
||||
{:error, _reason} = err ->
|
||||
err
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_rule(rule) do
|
||||
cond do
|
||||
not is_map(rule) ->
|
||||
{:error, "rule must be a map"}
|
||||
|
||||
not (Map.has_key?(rule, "mode") and is_binary(rule["mode"]) and
|
||||
rule["mode"] in ["contains_string", "matches_regex"]) ->
|
||||
{:error, "mode property must be a string, either 'contains_string' or 'matches_regex'"}
|
||||
|
||||
not (Map.has_key?(rule, "property") and is_binary(rule["property"]) and
|
||||
rule["property"] in ["url", "title", "author"]) ->
|
||||
{:error, "property property must be a string, either 'url', 'title', or 'author'"}
|
||||
|
||||
not (Map.has_key?(rule, "param") and is_binary(rule["param"])) ->
|
||||
{:error, "param property must be a string"}
|
||||
|
||||
not (Map.has_key?(rule, "weight") and is_integer(rule["weight"])) ->
|
||||
{:error, "weight property must be an integer"}
|
||||
|
||||
true ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp test(
|
||||
%{"mode" => mode, "property" => property, "param" => param, "weight" => weight},
|
||||
item_params
|
||||
|
|
|
@ -15,6 +15,9 @@ defmodule Frenzy.Pipeline.ScrapeStage do
|
|||
end
|
||||
end
|
||||
|
||||
@impl Stage
|
||||
def validate_opts(opts), do: {:ok, opts}
|
||||
|
||||
defp get_article_content(url) when is_binary(url) and url != "" do
|
||||
Logger.debug("Getting article from #{url}")
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
defmodule Frenzy.Pipeline.Stage do
|
||||
@callback apply(Map.t(), Map.t()) :: {:ok, Map.t()} | :tombstone | {:error, String.t()}
|
||||
|
||||
@callback validate_opts(Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
|
||||
end
|
||||
|
|
|
@ -65,7 +65,11 @@ defmodule FrenzyWeb.PipelineController do
|
|||
feed = conn.assigns[:feed]
|
||||
stage = conn.assigns[:stage]
|
||||
|
||||
with {:ok, options} <- Jason.decode(options_json) do
|
||||
with {:ok, options} <- Jason.decode(options_json),
|
||||
{:ok, options} <-
|
||||
apply(String.to_existing_atom("Elixir." <> stage.module_name), :validate_opts, [
|
||||
options
|
||||
]) do
|
||||
changeset = PipelineStage.changeset(stage, %{options: options})
|
||||
{:ok, _stage} = Repo.update(changeset)
|
||||
|
||||
|
@ -112,7 +116,9 @@ defmodule FrenzyWeb.PipelineController do
|
|||
feed = conn.assigns[:feed]
|
||||
|
||||
with {index, _} <- Integer.parse(index),
|
||||
{:ok, options} <- Jason.decode(options_json) do
|
||||
module_atom <- String.to_existing_atom("Elixir." <> module_name),
|
||||
{:ok, options} <- Jason.decode(options_json),
|
||||
{:ok, options} <- apply(module_atom, :validate_opts, [options]) do
|
||||
changeset =
|
||||
Ecto.build_assoc(feed, :pipeline_stages, %{
|
||||
index: index,
|
||||
|
|
Loading…
Reference in New Issue