Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit a07bdfb

Browse files
authored
Merge pull request #289 from coderplanets/enhance-editor-schema-validator
refactor(editor-export): enhance editor schema validator
2 parents 9d6cb01 + b77d204 commit a07bdfb

File tree

7 files changed

+246
-14
lines changed

7 files changed

+246
-14
lines changed

lib/helper/converter/editor_to_html/index.ex

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
# defmodule Helper.Converter.EditorToHTML.Parser do
2-
# @moduledoc false
3-
4-
# # TODO: map should be editor_block
5-
# @callback parse_block(editor_json :: Map.t()) :: String.t()
6-
# end
7-
81
defmodule Helper.Converter.EditorToHTML do
92
@moduledoc """
103
parse editor.js's json data to raw html and sanitize it

lib/helper/converter/editor_to_html/validator/editor_schema.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
4848

4949
def get("table") do
5050
[
51-
parent: %{"columnCount" => [:number], "items" => [:list]},
51+
parent: %{"columnCount" => [:number, min: 2], "items" => [:list]},
5252
item: %{
5353
"text" => [:string],
5454
"align" => [enum: @valid_table_align],

lib/helper/validator/schema.ex

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule Helper.Validator.Schema do
55
currently support boolean / string / number / enum
66
"""
77

8-
use Helper.Validator.Schema.Matchers, [:string, :number, :list, :boolean]
8+
# use Helper.Validator.Schema.Matchers, [:string, :number, :list, :boolean]
99

1010
@doc """
1111
cast data by given schema
@@ -49,10 +49,9 @@ defmodule Helper.Validator.Schema do
4949
end)
5050
end
5151

52-
# enum
5352
defp match(field, nil, enum: _, required: false), do: done(field, nil)
5453

55-
defp match(field, value, enum: enum, required: false) do
54+
defp match(field, value, enum: enum, required: _) do
5655
match(field, value, enum: enum)
5756
end
5857

@@ -70,9 +69,84 @@ defmodule Helper.Validator.Schema do
7069
end
7170
end
7271

72+
defp match(field, value, [type | options]) do
73+
match(field, value, type, options)
74+
end
75+
76+
defp match(field, nil, _type, [{:required, false} | _options]) do
77+
done(field, nil)
78+
end
79+
80+
defp match(field, value, type, [{:required, _} | options]) do
81+
match(field, value, type, options)
82+
end
83+
84+
# custom validate logic
85+
defp match(field, value, :string, [{:min, min} | options])
86+
when is_binary(value) and is_integer(min) do
87+
case String.length(value) >= min do
88+
true ->
89+
match(field, value, :string, options)
90+
91+
false ->
92+
error(field, value, :min, min)
93+
end
94+
end
95+
96+
defp match(field, value, :number, [{:min, min} | options])
97+
when is_integer(value) and is_integer(min) do
98+
case value >= min do
99+
true ->
100+
match(field, value, :number, options)
101+
102+
false ->
103+
error(field, value, :min, min)
104+
end
105+
end
106+
107+
# custom validate logic end
108+
109+
# main type
110+
defp match(field, value, :string, []) when is_binary(value), do: done(field, value)
111+
defp match(field, value, :number, []) when is_integer(value), do: done(field, value)
112+
defp match(field, value, :list, []) when is_list(value), do: done(field, value)
113+
defp match(field, value, :boolean, []) when is_boolean(value), do: done(field, value)
114+
# main type end
115+
116+
# judge option
117+
defp match(field, value, type, [option]) when is_tuple(option) do
118+
# 如果这里不判断的话会和下面的 match 冲突,是否有更好的写法?
119+
case option_valid?(option) do
120+
true ->
121+
error(field, value, type)
122+
123+
false ->
124+
{k, v} = option
125+
error(field, value, option: "#{to_string(k)}: #{to_string(v)}")
126+
end
127+
end
128+
129+
defp match(field, value, type, _), do: error(field, value, type)
130+
73131
defp done(field, value), do: {:ok, %{field: field, value: value}}
74132

133+
defp error(field, value, :min, min) do
134+
{:error, %{field: field |> to_string, value: value, message: "min size: #{min}"}}
135+
end
136+
137+
defp error(field, value, option: option) do
138+
{:error, %{field: field |> to_string, value: value, message: "unknow option: #{option}"}}
139+
end
140+
141+
defp error(field, value, :option) do
142+
{:error, %{field: field |> to_string, value: value, message: "unknow option"}}
143+
end
144+
75145
defp error(field, value, schema) do
76146
{:error, %{field: field |> to_string, value: value, message: "should be: #{schema}"}}
77147
end
148+
149+
defp option_valid?({:min, v}) when is_integer(v), do: true
150+
defp option_valid?({:required, v}) when is_boolean(v), do: true
151+
defp option_valid?(_), do: false
78152
end

test/helper/converter/editor_to_html_test/header_test.exs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Header do
127127
{:ok, editor_string} = Jason.encode(json)
128128
{:ok, converted} = Parser.to_html(editor_string)
129129

130-
IO.inspect(converted, label: "converted --")
131-
132130
assert Utils.str_occurence(converted, @eyebrow_class) == 0
133131
assert Utils.str_occurence(converted, @footer_class) == 1
134132
end

test/helper/converter/editor_to_html_test/list_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.List do
1212

1313
describe "[list block unit]" do
1414
defp set_items(mode, items) do
15-
editor_json = %{
15+
%{
1616
"time" => 1_567_250_876_713,
1717
"blocks" => [
1818
%{

test/helper/converter/editor_to_html_test/table_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Table do
119119
},
120120
%{block: "table", field: "items", message: "should be: list", value: "bb"}
121121
]
122+
123+
editor_json = set_items(-2, "bb")
124+
{:ok, editor_string} = Jason.encode(editor_json)
125+
{:error, err_msg} = Parser.to_html(editor_string)
126+
127+
assert err_msg == [
128+
%{block: "table", field: "columnCount", message: "min size: 2", value: -2},
129+
%{block: "table", field: "items", message: "should be: list", value: "bb"}
130+
]
122131
end
123132
end
124133
end
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
defmodule GroupherServer.Test.Helper.Validator.Schema do
2+
@moduledoc false
3+
4+
use GroupherServerWeb.ConnCase, async: true
5+
6+
alias Helper.Validator.Schema
7+
8+
describe "[basic schema]" do
9+
test "string with options" do
10+
schema = %{"text" => [:string, required: false]}
11+
data = %{"no_exsit" => "text"}
12+
assert {:ok, _} = Schema.cast(schema, data)
13+
14+
schema = %{"text" => [:string, required: true]}
15+
data = %{"no_exsit" => "text"}
16+
{:error, error} = Schema.cast(schema, data)
17+
assert error == [%{field: "text", message: "should be: string", value: nil}]
18+
19+
schema = %{"text" => [:string, required: true]}
20+
data = %{"text" => "text"}
21+
assert {:ok, _} = Schema.cast(schema, data)
22+
23+
schema = %{"text" => [:string, min: 5]}
24+
data = %{"text" => "text"}
25+
{:error, error} = Schema.cast(schema, data)
26+
assert error == [%{field: "text", message: "min size: 5", value: "text"}]
27+
28+
schema = %{"text" => [:string, required: false, min: 5]}
29+
data = %{"text" => "text"}
30+
{:error, error} = Schema.cast(schema, data)
31+
assert error == [%{field: "text", message: "min size: 5", value: "text"}]
32+
33+
schema = %{"text" => [:string, min: 5]}
34+
data = %{"no_exsit" => "text"}
35+
{:error, error} = Schema.cast(schema, data)
36+
assert error == [%{field: "text", message: "should be: string", value: nil}]
37+
38+
schema = %{"text" => [:string, required: true, min: 5]}
39+
data = %{"no_exsit" => "text"}
40+
{:error, error} = Schema.cast(schema, data)
41+
assert error == [%{field: "text", message: "should be: string", value: nil}]
42+
43+
schema = %{"text" => [:string, required: true, min: "5"]}
44+
data = %{"text" => "text"}
45+
{:error, error} = Schema.cast(schema, data)
46+
assert error == [%{field: "text", message: "unknow option: min: 5", value: "text"}]
47+
# IO.inspect(Schema.cast(schema, data), label: "schema result")
48+
end
49+
50+
test "number with options" do
51+
schema = %{"text" => [:number, required: false]}
52+
data = %{"no_exsit" => 1}
53+
assert {:ok, _} = Schema.cast(schema, data)
54+
55+
schema = %{"text" => [:number, required: true]}
56+
data = %{"no_exsit" => 1}
57+
{:error, error} = Schema.cast(schema, data)
58+
assert error == [%{field: "text", message: "should be: number", value: nil}]
59+
60+
schema = %{"text" => [:number, required: true]}
61+
data = %{"text" => 1}
62+
assert {:ok, _} = Schema.cast(schema, data)
63+
64+
schema = %{"text" => [:number, min: 5]}
65+
data = %{"text" => 4}
66+
{:error, error} = Schema.cast(schema, data)
67+
assert error == [%{field: "text", message: "min size: 5", value: 4}]
68+
69+
schema = %{"text" => [:number, required: false, min: 5]}
70+
data = %{"text" => 4}
71+
{:error, error} = Schema.cast(schema, data)
72+
assert error == [%{field: "text", message: "min size: 5", value: 4}]
73+
74+
schema = %{"text" => [:number, min: 5]}
75+
data = %{"no_exsit" => 4}
76+
{:error, error} = Schema.cast(schema, data)
77+
assert error == [%{field: "text", message: "should be: number", value: nil}]
78+
79+
schema = %{"text" => [:number, required: true, min: 5]}
80+
data = %{"no_exsit" => 1}
81+
{:error, error} = Schema.cast(schema, data)
82+
assert error == [%{field: "text", message: "should be: number", value: nil}]
83+
84+
# IO.inspect(Schema.cast(schema, data), label: "schema result")
85+
# hello world
86+
end
87+
88+
test "number with wrong option" do
89+
schema = %{"text" => [:number, required: true, min: "5"]}
90+
data = %{"text" => 1}
91+
92+
{:error, error} = Schema.cast(schema, data)
93+
assert error == [%{field: "text", message: "unknow option: min: 5", value: 1}]
94+
95+
schema = %{"text" => [:number, required: true, no_exsit_option: "xxx"]}
96+
data = %{"text" => 1}
97+
98+
{:error, error} = Schema.cast(schema, data)
99+
assert error == [%{field: "text", message: "unknow option: no_exsit_option: xxx", value: 1}]
100+
end
101+
102+
test "number with options edage case" do
103+
schema = %{"text" => [:number, min: 2]}
104+
data = %{"text" => "aa"}
105+
106+
{:error, error} = Schema.cast(schema, data)
107+
assert error == [%{field: "text", message: "should be: number", value: "aa"}]
108+
end
109+
110+
test "list with options" do
111+
schema = %{"text" => [:list, required: false]}
112+
data = %{"no_exsit" => []}
113+
assert {:ok, _} = Schema.cast(schema, data)
114+
115+
schema = %{"text" => [:list, required: true]}
116+
data = %{"no_exsit" => []}
117+
{:error, error} = Schema.cast(schema, data)
118+
assert error == [%{field: "text", message: "should be: list", value: nil}]
119+
120+
schema = %{"text" => [:list, required: true]}
121+
data = %{"text" => []}
122+
assert {:ok, _} = Schema.cast(schema, data)
123+
end
124+
125+
test "boolean with options" do
126+
schema = %{"text" => [:boolean, required: false]}
127+
data = %{"no_exsit" => false}
128+
assert {:ok, _} = Schema.cast(schema, data)
129+
130+
schema = %{"text" => [:boolean, required: true]}
131+
data = %{"no_exsit" => false}
132+
{:error, error} = Schema.cast(schema, data)
133+
assert error == [%{field: "text", message: "should be: boolean", value: nil}]
134+
135+
schema = %{"text" => [:boolean, required: true]}
136+
data = %{"text" => false}
137+
assert {:ok, _} = Schema.cast(schema, data)
138+
end
139+
140+
test "enum with options" do
141+
schema = %{"text" => [enum: [1, 2, 3], required: false]}
142+
data = %{"no_exsit" => false}
143+
assert {:ok, _} = Schema.cast(schema, data)
144+
145+
schema = %{"text" => [enum: [1, 2, 3], required: true]}
146+
data = %{"no_exsit" => false}
147+
{:error, error} = Schema.cast(schema, data)
148+
assert error == [%{field: "text", message: "should be: 1 | 2 | 3"}]
149+
150+
schema = %{"text" => [enum: [1, 2, 3]]}
151+
data = %{"text" => 1}
152+
assert {:ok, _} = Schema.cast(schema, data)
153+
154+
# IO.inspect(Schema.cast(schema, data), label: "schema result")
155+
# hello world
156+
end
157+
end
158+
end

0 commit comments

Comments
 (0)