diff --git a/lib/helper/converter/editor_to_html/index.ex b/lib/helper/converter/editor_to_html/index.ex index 04b123f89..3538bb9f0 100644 --- a/lib/helper/converter/editor_to_html/index.ex +++ b/lib/helper/converter/editor_to_html/index.ex @@ -1,10 +1,3 @@ -# defmodule Helper.Converter.EditorToHTML.Parser do -# @moduledoc false - -# # TODO: map should be editor_block -# @callback parse_block(editor_json :: Map.t()) :: String.t() -# end - defmodule Helper.Converter.EditorToHTML do @moduledoc """ parse editor.js's json data to raw html and sanitize it diff --git a/lib/helper/converter/editor_to_html/validator/editor_schema.ex b/lib/helper/converter/editor_to_html/validator/editor_schema.ex index 2d2840269..4d5449560 100644 --- a/lib/helper/converter/editor_to_html/validator/editor_schema.ex +++ b/lib/helper/converter/editor_to_html/validator/editor_schema.ex @@ -48,7 +48,7 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do def get("table") do [ - parent: %{"columnCount" => [:number], "items" => [:list]}, + parent: %{"columnCount" => [:number, min: 2], "items" => [:list]}, item: %{ "text" => [:string], "align" => [enum: @valid_table_align], diff --git a/lib/helper/validator/schema.ex b/lib/helper/validator/schema.ex index bef9f2969..a56f1f4f2 100644 --- a/lib/helper/validator/schema.ex +++ b/lib/helper/validator/schema.ex @@ -5,7 +5,7 @@ defmodule Helper.Validator.Schema do currently support boolean / string / number / enum """ - use Helper.Validator.Schema.Matchers, [:string, :number, :list, :boolean] + # use Helper.Validator.Schema.Matchers, [:string, :number, :list, :boolean] @doc """ cast data by given schema @@ -49,10 +49,9 @@ defmodule Helper.Validator.Schema do end) end - # enum defp match(field, nil, enum: _, required: false), do: done(field, nil) - defp match(field, value, enum: enum, required: false) do + defp match(field, value, enum: enum, required: _) do match(field, value, enum: enum) end @@ -70,9 +69,84 @@ defmodule Helper.Validator.Schema do end end + defp match(field, value, [type | options]) do + match(field, value, type, options) + end + + defp match(field, nil, _type, [{:required, false} | _options]) do + done(field, nil) + end + + defp match(field, value, type, [{:required, _} | options]) do + match(field, value, type, options) + end + + # custom validate logic + defp match(field, value, :string, [{:min, min} | options]) + when is_binary(value) and is_integer(min) do + case String.length(value) >= min do + true -> + match(field, value, :string, options) + + false -> + error(field, value, :min, min) + end + end + + defp match(field, value, :number, [{:min, min} | options]) + when is_integer(value) and is_integer(min) do + case value >= min do + true -> + match(field, value, :number, options) + + false -> + error(field, value, :min, min) + end + end + + # custom validate logic end + + # main type + defp match(field, value, :string, []) when is_binary(value), do: done(field, value) + defp match(field, value, :number, []) when is_integer(value), do: done(field, value) + defp match(field, value, :list, []) when is_list(value), do: done(field, value) + defp match(field, value, :boolean, []) when is_boolean(value), do: done(field, value) + # main type end + + # judge option + defp match(field, value, type, [option]) when is_tuple(option) do + # 如果这里不判断的话会和下面的 match 冲突,是否有更好的写法? + case option_valid?(option) do + true -> + error(field, value, type) + + false -> + {k, v} = option + error(field, value, option: "#{to_string(k)}: #{to_string(v)}") + end + end + + defp match(field, value, type, _), do: error(field, value, type) + defp done(field, value), do: {:ok, %{field: field, value: value}} + defp error(field, value, :min, min) do + {:error, %{field: field |> to_string, value: value, message: "min size: #{min}"}} + end + + defp error(field, value, option: option) do + {:error, %{field: field |> to_string, value: value, message: "unknow option: #{option}"}} + end + + defp error(field, value, :option) do + {:error, %{field: field |> to_string, value: value, message: "unknow option"}} + end + defp error(field, value, schema) do {:error, %{field: field |> to_string, value: value, message: "should be: #{schema}"}} end + + defp option_valid?({:min, v}) when is_integer(v), do: true + defp option_valid?({:required, v}) when is_boolean(v), do: true + defp option_valid?(_), do: false end diff --git a/test/helper/converter/editor_to_html_test/header_test.exs b/test/helper/converter/editor_to_html_test/header_test.exs index 3b61e067c..bac2f08cd 100644 --- a/test/helper/converter/editor_to_html_test/header_test.exs +++ b/test/helper/converter/editor_to_html_test/header_test.exs @@ -127,8 +127,6 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Header do {:ok, editor_string} = Jason.encode(json) {:ok, converted} = Parser.to_html(editor_string) - IO.inspect(converted, label: "converted --") - assert Utils.str_occurence(converted, @eyebrow_class) == 0 assert Utils.str_occurence(converted, @footer_class) == 1 end diff --git a/test/helper/converter/editor_to_html_test/list_test.exs b/test/helper/converter/editor_to_html_test/list_test.exs index 795655d2e..7577a0c4d 100644 --- a/test/helper/converter/editor_to_html_test/list_test.exs +++ b/test/helper/converter/editor_to_html_test/list_test.exs @@ -12,7 +12,7 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.List do describe "[list block unit]" do defp set_items(mode, items) do - editor_json = %{ + %{ "time" => 1_567_250_876_713, "blocks" => [ %{ diff --git a/test/helper/converter/editor_to_html_test/table_test.exs b/test/helper/converter/editor_to_html_test/table_test.exs index 44e64262b..acf1885bb 100644 --- a/test/helper/converter/editor_to_html_test/table_test.exs +++ b/test/helper/converter/editor_to_html_test/table_test.exs @@ -119,6 +119,15 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Table do }, %{block: "table", field: "items", message: "should be: list", value: "bb"} ] + + editor_json = set_items(-2, "bb") + {:ok, editor_string} = Jason.encode(editor_json) + {:error, err_msg} = Parser.to_html(editor_string) + + assert err_msg == [ + %{block: "table", field: "columnCount", message: "min size: 2", value: -2}, + %{block: "table", field: "items", message: "should be: list", value: "bb"} + ] end end end diff --git a/test/helper/validator/schema_test.exs b/test/helper/validator/schema_test.exs new file mode 100644 index 000000000..690204f03 --- /dev/null +++ b/test/helper/validator/schema_test.exs @@ -0,0 +1,158 @@ +defmodule GroupherServer.Test.Helper.Validator.Schema do + @moduledoc false + + use GroupherServerWeb.ConnCase, async: true + + alias Helper.Validator.Schema + + describe "[basic schema]" do + test "string with options" do + schema = %{"text" => [:string, required: false]} + data = %{"no_exsit" => "text"} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:string, required: true]} + data = %{"no_exsit" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: string", value: nil}] + + schema = %{"text" => [:string, required: true]} + data = %{"text" => "text"} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:string, min: 5]} + data = %{"text" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "min size: 5", value: "text"}] + + schema = %{"text" => [:string, required: false, min: 5]} + data = %{"text" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "min size: 5", value: "text"}] + + schema = %{"text" => [:string, min: 5]} + data = %{"no_exsit" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: string", value: nil}] + + schema = %{"text" => [:string, required: true, min: 5]} + data = %{"no_exsit" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: string", value: nil}] + + schema = %{"text" => [:string, required: true, min: "5"]} + data = %{"text" => "text"} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "unknow option: min: 5", value: "text"}] + # IO.inspect(Schema.cast(schema, data), label: "schema result") + end + + test "number with options" do + schema = %{"text" => [:number, required: false]} + data = %{"no_exsit" => 1} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:number, required: true]} + data = %{"no_exsit" => 1} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: number", value: nil}] + + schema = %{"text" => [:number, required: true]} + data = %{"text" => 1} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:number, min: 5]} + data = %{"text" => 4} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "min size: 5", value: 4}] + + schema = %{"text" => [:number, required: false, min: 5]} + data = %{"text" => 4} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "min size: 5", value: 4}] + + schema = %{"text" => [:number, min: 5]} + data = %{"no_exsit" => 4} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: number", value: nil}] + + schema = %{"text" => [:number, required: true, min: 5]} + data = %{"no_exsit" => 1} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: number", value: nil}] + + # IO.inspect(Schema.cast(schema, data), label: "schema result") + # hello world + end + + test "number with wrong option" do + schema = %{"text" => [:number, required: true, min: "5"]} + data = %{"text" => 1} + + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "unknow option: min: 5", value: 1}] + + schema = %{"text" => [:number, required: true, no_exsit_option: "xxx"]} + data = %{"text" => 1} + + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "unknow option: no_exsit_option: xxx", value: 1}] + end + + test "number with options edage case" do + schema = %{"text" => [:number, min: 2]} + data = %{"text" => "aa"} + + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: number", value: "aa"}] + end + + test "list with options" do + schema = %{"text" => [:list, required: false]} + data = %{"no_exsit" => []} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:list, required: true]} + data = %{"no_exsit" => []} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: list", value: nil}] + + schema = %{"text" => [:list, required: true]} + data = %{"text" => []} + assert {:ok, _} = Schema.cast(schema, data) + end + + test "boolean with options" do + schema = %{"text" => [:boolean, required: false]} + data = %{"no_exsit" => false} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [:boolean, required: true]} + data = %{"no_exsit" => false} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: boolean", value: nil}] + + schema = %{"text" => [:boolean, required: true]} + data = %{"text" => false} + assert {:ok, _} = Schema.cast(schema, data) + end + + test "enum with options" do + schema = %{"text" => [enum: [1, 2, 3], required: false]} + data = %{"no_exsit" => false} + assert {:ok, _} = Schema.cast(schema, data) + + schema = %{"text" => [enum: [1, 2, 3], required: true]} + data = %{"no_exsit" => false} + {:error, error} = Schema.cast(schema, data) + assert error == [%{field: "text", message: "should be: 1 | 2 | 3"}] + + schema = %{"text" => [enum: [1, 2, 3]]} + data = %{"text" => 1} + assert {:ok, _} = Schema.cast(schema, data) + + # IO.inspect(Schema.cast(schema, data), label: "schema result") + # hello world + end + end +end