praxis 2.0.pre.8 → 2.0.pre.9
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2a11ec74ee5a52178fe7aae10c503eb61407c739c40c262386e855e1abd40ee
|
4
|
+
data.tar.gz: 71b397991329ea9726b366938de75768bedf812324e4b2d768ac7dae3f25e33e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21fbd6dbb60486cea3ec5cdd18a1b4178873ff6343182f2b44a11d71cbdac1664bec005760b77511de342fc92a63abe7864c85f10ffc1c3953734a1069f2520d
|
7
|
+
data.tar.gz: 7c0f8a5c417ad9ecd76fd67e08f1f219cc274c3bbd30ec88d7ae669e0a10d4ec5585c365ad7c3a38163b3d4f367897e7129bbbda66664947e82c37dc90213f08
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
## next
|
4
4
|
|
5
|
+
## 2.0.pre.9
|
6
|
+
|
7
|
+
- Refined OpenAPI doc generation to output only non-null attributes in the InfoObject.
|
8
|
+
- Fixed filtering params validation to properly allow null values for the "!" and "!!" operators
|
9
|
+
|
5
10
|
## 2.0.pre.6
|
6
11
|
|
7
12
|
- Removed the explicit `links` helpers from a `MediaType`. There was too much magic and assumptions built into it. Things can still be built in a custom basis (or through a plugin) if necessary.
|
@@ -10,20 +10,28 @@ module Praxis
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def dump
|
13
|
-
data ={
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
data = { version: version }
|
14
|
+
[
|
15
|
+
:title,
|
16
|
+
:description,
|
17
|
+
:termsOfService,
|
18
|
+
:contact,
|
19
|
+
:license
|
20
|
+
].each do |attr|
|
21
|
+
val = info.send(attr)
|
22
|
+
data[attr] = val if val
|
23
|
+
end
|
24
|
+
|
25
|
+
# Special attributes
|
26
|
+
data[:'x-name'] = info.name
|
27
|
+
if info.logo_url
|
28
|
+
data[:'x-logo'] = {
|
22
29
|
url: info.logo_url,
|
23
30
|
backgroundColor: "#FFFFFF",
|
24
31
|
altText: info.title
|
25
32
|
}
|
26
|
-
|
33
|
+
end
|
34
|
+
data
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
@@ -166,7 +166,6 @@ module Praxis
|
|
166
166
|
end
|
167
167
|
|
168
168
|
attr_name = match[:attribute].to_sym
|
169
|
-
# TODO: we should coerce values if there's a mediatype defined?
|
170
169
|
coerced = if media_type
|
171
170
|
filter_components = attr_name.to_s.split('.').map(&:to_sym)
|
172
171
|
attr, _enclosing_type = find_filter_attribute(filter_components, media_type)
|
@@ -217,21 +216,9 @@ module Praxis
|
|
217
216
|
errors << "Operator #{item[:op]} not allowed for filter #{attr_name}"
|
218
217
|
end
|
219
218
|
value_type = attr_filters[:value_type]
|
220
|
-
value = item[:value]
|
221
|
-
if value_type && !value_type.valid_type?(value)
|
222
|
-
# Allow a collection of values of the right type for multimatch (if operators are = or !=)
|
223
|
-
if ['=','!='].include?(item[:op])
|
224
|
-
coll_type = Attributor::Collection.of(value_type)
|
225
|
-
if !coll_type.valid_type?(value)
|
226
|
-
errors << "Invalid type in filter/s value for #{attr_name} " +\
|
227
|
-
"(one or more of the multiple matches in #{value} are not a #{value_type.name.split('::').last})"
|
228
|
-
end
|
229
|
-
else
|
230
|
-
errors << "Invalid type in filter value for #{attr_name} (#{value} using '#{item[:op]}' is not a #{value_type.name.split('::').last})"
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
219
|
next unless value_type == Attributor::String
|
220
|
+
|
221
|
+
value = item[:value]
|
235
222
|
unless value.empty?
|
236
223
|
fuzzy_match = attr_filters[:fuzzy_match]
|
237
224
|
if (value[-1] == '*' || value[0] == '*') && !fuzzy_match
|
data/lib/praxis/version.rb
CHANGED
@@ -30,5 +30,111 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
|
|
30
30
|
])
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
context 'with an associated MediaType' do
|
35
|
+
let(:params_for_post_media_type) do
|
36
|
+
# Note wrap the filter_params (.for) type in an attribute (which then we discard), so it will
|
37
|
+
# construct it propertly by applying the block. Seems easier than creating the type alone, and
|
38
|
+
# then manually apply the block
|
39
|
+
Attributor::Attribute.new(described_class.for(Post)) do
|
40
|
+
filter 'id', using: ['=', '!=', '!']
|
41
|
+
end.type
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with a single value' do
|
45
|
+
let(:str) { 'id=1' }
|
46
|
+
it 'coerces its value to the associated mediatype attribute type' do
|
47
|
+
parsed = params_for_post_media_type.load(str).parsed_array
|
48
|
+
expect(parsed.first).to eq(:name=>:id, :op=>"=", :value=>1)
|
49
|
+
expect(Post.attributes[:id].type.valid_type?(parsed.first[:value])).to be_truthy
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with multimatch' do
|
54
|
+
let(:str) { 'id=1,2,3' }
|
55
|
+
it 'coerces ALL csv values to the associated mediatype attribute type' do
|
56
|
+
parsed = params_for_post_media_type.load(str).parsed_array
|
57
|
+
expect(parsed.first).to eq(:name=>:id, :op=>"=", :value=>[1, 2, 3])
|
58
|
+
parsed.first[:value].each do |val|
|
59
|
+
expect(Post.attributes[:id].type.valid_type?(val)).to be_truthy
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with a single value that is null' do
|
65
|
+
let(:str) { 'id!' }
|
66
|
+
it 'properly loads it as null' do
|
67
|
+
parsed = params_for_post_media_type.load(str).parsed_array
|
68
|
+
expect(parsed.first).to eq(:name=>:id, :op=>"!", :value=>nil)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
context '.validate' do
|
76
|
+
let(:filtering_params_type) do
|
77
|
+
# Note wrap the filter_params (.for) type in an attribute (which then we discard), so it will
|
78
|
+
# construct it propertly by applying the block. Seems easier than creating the type alone, and
|
79
|
+
# then manually apply the block
|
80
|
+
Attributor::Attribute.new(described_class.for(Post)) do
|
81
|
+
filter 'id', using: ['=', '!=']
|
82
|
+
filter 'title', using: ['=', '!='], fuzzy: true
|
83
|
+
filter 'content', using: ['=', '!=']
|
84
|
+
end.type
|
85
|
+
end
|
86
|
+
let(:loaded_params) { filtering_params_type.load(filters_string) }
|
87
|
+
subject { loaded_params.validate(filters_string) }
|
88
|
+
|
89
|
+
context 'errors' do
|
90
|
+
context 'given attributes that do not exist in the type' do
|
91
|
+
let(:filters_string) { 'NotAnExistingAttribute=Foobar*'}
|
92
|
+
it 'raises an error' do
|
93
|
+
expect{subject}.to raise_error(/NotAnExistingAttribute.*does not exist/)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'given unallowed attributes' do
|
98
|
+
let(:filters_string) { 'href=Foobar*'}
|
99
|
+
it 'raises an error' do
|
100
|
+
expect(subject).to_not be_empty
|
101
|
+
matches_error = subject.any? {|err| err =~ /Filtering by href is not allowed/}
|
102
|
+
expect(matches_error).to be_truthy
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'given unallowed operator' do
|
107
|
+
let(:filters_string) { 'title>Foobar*'}
|
108
|
+
it 'raises an error' do
|
109
|
+
expect(subject).to_not be_empty
|
110
|
+
expect(subject.first).to match(/Operator > not allowed for filter title/)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
context 'fuzzy matches' do
|
115
|
+
context 'when allowed' do
|
116
|
+
context 'given a fuzzy string' do
|
117
|
+
let(:filters_string) { 'title=IAmAString*'}
|
118
|
+
it 'validates properly' do
|
119
|
+
expect(subject).to be_empty
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
context 'when NOT allowed' do
|
124
|
+
context 'given a fuzzy string' do
|
125
|
+
let(:filters_string) { 'content=IAmAString*'}
|
126
|
+
it 'errors out' do
|
127
|
+
expect(subject).to_not be_empty
|
128
|
+
expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
context 'given a non-fuzzy string' do
|
132
|
+
let(:filters_string) { 'content=IAmAString'}
|
133
|
+
it 'validates properly' do
|
134
|
+
expect(subject).to be_empty
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
33
139
|
end
|
34
140
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: praxis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.pre.
|
4
|
+
version: 2.0.pre.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-11-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -758,7 +758,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
758
758
|
- !ruby/object:Gem::Version
|
759
759
|
version: 1.3.1
|
760
760
|
requirements: []
|
761
|
-
rubygems_version: 3.
|
761
|
+
rubygems_version: 3.1.2
|
762
762
|
signing_key:
|
763
763
|
specification_version: 4
|
764
764
|
summary: Building APIs the way you want it.
|