manageiq-api-common 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +22 -0
- data/lib/manageiq/api/common/application_controller_mixins/parameters.rb +6 -2
- data/lib/manageiq/api/common/application_controller_mixins/request_parameter_validation.rb +29 -0
- data/lib/manageiq/api/common/graphql.rb +1 -0
- data/lib/manageiq/api/common/graphql/templates/query_type.erb +7 -5
- data/lib/manageiq/api/common/graphql/types/query_sort_by.rb +16 -0
- data/lib/manageiq/api/common/open_api/docs/doc_v3.rb +10 -0
- data/lib/manageiq/api/common/open_api/generator.rb +19 -1
- data/lib/manageiq/api/common/paginated_response.rb +22 -3
- data/lib/manageiq/api/common/rbac/query_shared_resource.rb +1 -1
- data/lib/manageiq/api/common/rbac/share_resource.rb +1 -1
- data/lib/manageiq/api/common/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46a97632c285025bf8e8f2d7204409a6afb43b29b2781a72dcceba180770622e
|
4
|
+
data.tar.gz: a9574eb959db384c326bcc9b591a3a462e7991f1be340d1d8747712b9e5eea2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 835d73ceb6bdbec6e860eb5ff0853282e90927cebe254b0eedf0edae535ce40264367fd0130a172a7f3be0ff02cd5aa2f92a5451c193554f88961b1e693202a5
|
7
|
+
data.tar.gz: ca867c61681bd9566cb68dcc20763c9ce2df4977202b0b4637f56f85f61a17ce8d90dcffa4148d125e798cb510097a770357c6cd87575be224422cd2f0cc67d3
|
data/README.md
CHANGED
@@ -67,6 +67,28 @@ After implementing filtering in your application, this is the way to filter via
|
|
67
67
|
|"?filter[id][]=5&filter[id][]=10&filter[id][]=15&filter[id][]=20"|`{:filter => { :id => ["5", "10", "15", "20"]}}` <br> **`filter: { id: ["5", "10", "15", "20"] }`**|
|
68
68
|
|"?filter[id][eq][]=5&filter[id][eq][]=10&filter[id][eq][]=15&filter[id][eq][]=20"|`{:filter => { :id => { :eq => ["5", "10", "15", "20"]}}}` <br> **`filter: { id: { eq: ["5", "10", "15", "20"] }`**|
|
69
69
|
|
70
|
+
#### Sorting Results
|
71
|
+
|
72
|
+
Sorting query results is controlled via the _sort_by_ query parameter. The _sort_by_ parameter is available for both REST API and GraphQL requests.
|
73
|
+
|
74
|
+
The syntax for the _sort_by_ parameter supports:
|
75
|
+
|
76
|
+
- a single string representing the attribute name to sort by which may be followed by :asc or :desc
|
77
|
+
- **attribute** (_default order is ascending_)
|
78
|
+
- **attribute:asc** (_ascending order_)
|
79
|
+
- **attribute:desc** (_descending order_)
|
80
|
+
- an array of strings of the above syntax
|
81
|
+
|
82
|
+
##### Sort_by Examples:
|
83
|
+
|
84
|
+
- GET /api/v1.0/sources?sort_by=name
|
85
|
+
- GET /api/v1.0/vms?sort_by[]=power_state\&sort_by[]=memory:desc
|
86
|
+
|
87
|
+
| Query Parameter | Ruby Client Parameter | GraphQL Parameter |
|
88
|
+
| --------------- | --------------------- | ----------------- |
|
89
|
+
| "?sort_by=name" | { :sort_by => "name" } | sort_by: "name" |
|
90
|
+
| "?sort_by[]=power_state\&sort_by[]=memory:desc" | { :sort_by => ["power_state", "memory:desc"] } | sort_by: ["power_state, "memory:desc"] |
|
91
|
+
|
70
92
|
## Development
|
71
93
|
|
72
94
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -17,12 +17,12 @@ module ManageIQ
|
|
17
17
|
def safe_params_for_list
|
18
18
|
check_if_openapi_enabled
|
19
19
|
# :limit & :offset can be passed in for pagination purposes, but shouldn't show up as params for filtering purposes
|
20
|
-
@safe_params_for_list ||= params.merge(params_for_polymorphic_subcollection).permit(*permitted_params, :filter => {})
|
20
|
+
@safe_params_for_list ||= params.merge(params_for_polymorphic_subcollection).permit(*permitted_params, :filter => {}, :sort_by => [])
|
21
21
|
end
|
22
22
|
|
23
23
|
def permitted_params
|
24
24
|
check_if_openapi_enabled
|
25
|
-
api_doc_definition.all_attributes + [:limit, :offset] + [subcollection_foreign_key]
|
25
|
+
api_doc_definition.all_attributes + [:limit, :offset, :sort_by] + [subcollection_foreign_key]
|
26
26
|
end
|
27
27
|
|
28
28
|
def subcollection_foreign_key
|
@@ -98,6 +98,10 @@ module ManageIQ
|
|
98
98
|
safe_params_for_list[:offset]
|
99
99
|
end
|
100
100
|
|
101
|
+
def query_sort_by
|
102
|
+
safe_params_for_list[:sort_by]
|
103
|
+
end
|
104
|
+
|
101
105
|
def params_for_update
|
102
106
|
check_if_openapi_enabled
|
103
107
|
body_params.permit(*api_doc_definition.all_attributes - api_doc_definition.read_only_attributes)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ManageIQ
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module ApplicationControllerMixins
|
5
|
+
module RequestParameterValidation
|
6
|
+
def self.included(other)
|
7
|
+
other.include(OpenapiEnabled)
|
8
|
+
|
9
|
+
other.before_action(:validate_request_parameters)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def validate_request_parameters
|
15
|
+
api_version = self.class.send(:api_version)[1..-1].sub(/x/, ".")
|
16
|
+
|
17
|
+
api_doc.try(
|
18
|
+
:validate_parameters!,
|
19
|
+
request.method,
|
20
|
+
request.path,
|
21
|
+
api_version,
|
22
|
+
params.slice(:sort_by)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -8,6 +8,7 @@ require "manageiq/api/common/graphql/generator"
|
|
8
8
|
require "manageiq/api/common/graphql/types/big_int"
|
9
9
|
require "manageiq/api/common/graphql/types/date_time"
|
10
10
|
require "manageiq/api/common/graphql/types/query_filter"
|
11
|
+
require "manageiq/api/common/graphql/types/query_sort_by"
|
11
12
|
|
12
13
|
module ManageIQ
|
13
14
|
module API
|
@@ -18,10 +18,12 @@ QueryType = ::GraphQL::ObjectType.define do
|
|
18
18
|
description "List available #{collection}"
|
19
19
|
type types[resource_type]
|
20
20
|
|
21
|
-
argument :id,
|
22
|
-
argument :offset,
|
23
|
-
argument :limit,
|
24
|
-
argument :filter,
|
21
|
+
argument :id, types.ID
|
22
|
+
argument :offset, types.Int, "The number of #{collection} to skip before starting to collect the result set"
|
23
|
+
argument :limit, types.Int, "The number of #{collection} to return"
|
24
|
+
argument :filter, ::ManageIQ::API::Common::GraphQL::Types::QueryFilter, "The Query Filter for querying the #{collection}"
|
25
|
+
argument :sort_by, ::ManageIQ::API::Common::GraphQL::Types::QuerySortBy, "The optional attributes to sort by. Provided as an array of attr[:asc] and attr:desc values"
|
26
|
+
|
25
27
|
resolve lambda { |_obj, args, ctx|
|
26
28
|
if base_query.present?
|
27
29
|
scope = base_query.call(model_class, ctx)
|
@@ -39,7 +41,7 @@ QueryType = ::GraphQL::ObjectType.define do
|
|
39
41
|
end
|
40
42
|
scope = ::ManageIQ::API::Common::GraphQL.search_options(scope, args)
|
41
43
|
::ManageIQ::API::Common::PaginatedResponse.new(
|
42
|
-
base_query: scope, request: nil, limit: args[:limit], offset: args[:offset]
|
44
|
+
base_query: scope, request: nil, limit: args[:limit], offset: args[:offset], sort_by: args[:sort_by]
|
43
45
|
).records
|
44
46
|
}
|
45
47
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ManageIQ
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module GraphQL
|
5
|
+
module Types
|
6
|
+
QuerySortBy = ::GraphQL::ScalarType.define do
|
7
|
+
name "QuerySortBy"
|
8
|
+
description "The Query SortBy"
|
9
|
+
|
10
|
+
coerce_input ->(value, _ctx) { JSON.parse(value.to_json) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -34,6 +34,16 @@ module ManageIQ
|
|
34
34
|
request_operation.validate_request_body(payload_content_type, payload)
|
35
35
|
end
|
36
36
|
|
37
|
+
def validate_parameters!(http_method, request_path, api_version, params)
|
38
|
+
path = request_path.split(api_version)[1]
|
39
|
+
raise "API version not found in request_path" if path.nil?
|
40
|
+
|
41
|
+
request_operation = validator_doc.request_operation(http_method.to_s.downcase, path)
|
42
|
+
return unless request_operation
|
43
|
+
|
44
|
+
request_operation.validate_request_parameter(params, {})
|
45
|
+
end
|
46
|
+
|
37
47
|
def version
|
38
48
|
@version ||= Gem::Version.new(content.fetch_path("info", "version"))
|
39
49
|
end
|
@@ -97,6 +97,11 @@ module ManageIQ
|
|
97
97
|
"pattern" => "^\\d+$",
|
98
98
|
"readOnly" => true,
|
99
99
|
},
|
100
|
+
"SortByAttribute" => {
|
101
|
+
"type" => "string",
|
102
|
+
"description" => "Attribute with optional order to sort the result set by.",
|
103
|
+
"pattern" => "^[a-z\\-_]+(:asc|:desc)?$"
|
104
|
+
}
|
100
105
|
}
|
101
106
|
end
|
102
107
|
|
@@ -169,6 +174,18 @@ module ManageIQ
|
|
169
174
|
"default" => 0
|
170
175
|
}
|
171
176
|
},
|
177
|
+
"QuerySortBy" => {
|
178
|
+
"in" => "query",
|
179
|
+
"name" => "sort_by",
|
180
|
+
"description" => "The list of attribute and order to sort the result set by.",
|
181
|
+
"required" => false,
|
182
|
+
"schema" => {
|
183
|
+
"oneOf" => [
|
184
|
+
{ "$ref" => "##{SCHEMAS_PATH}/SortByAttribute" },
|
185
|
+
{ "type" => "array", "items" => { "$ref" => "##{SCHEMAS_PATH}/SortByAttribute" } }
|
186
|
+
]
|
187
|
+
}
|
188
|
+
}
|
172
189
|
}
|
173
190
|
end
|
174
191
|
|
@@ -194,7 +211,8 @@ module ManageIQ
|
|
194
211
|
"parameters" => [
|
195
212
|
{ "$ref" => "##{PARAMETERS_PATH}/QueryLimit" },
|
196
213
|
{ "$ref" => "##{PARAMETERS_PATH}/QueryOffset" },
|
197
|
-
{ "$ref" => "##{PARAMETERS_PATH}/QueryFilter" }
|
214
|
+
{ "$ref" => "##{PARAMETERS_PATH}/QueryFilter" },
|
215
|
+
{ "$ref" => "##{PARAMETERS_PATH}/QuerySortBy" }
|
198
216
|
],
|
199
217
|
"responses" => {
|
200
218
|
"200" => {
|
@@ -2,17 +2,23 @@ module ManageIQ
|
|
2
2
|
module API
|
3
3
|
module Common
|
4
4
|
class PaginatedResponse
|
5
|
-
attr_reader :limit, :offset
|
5
|
+
attr_reader :limit, :offset, :sort_by
|
6
6
|
|
7
|
-
def initialize(base_query:, request:, limit: nil, offset: nil)
|
7
|
+
def initialize(base_query:, request:, limit: nil, offset: nil, sort_by: nil)
|
8
8
|
@base_query = base_query
|
9
9
|
@request = request
|
10
10
|
@limit = (limit || 100).to_i.clamp(1, 1000)
|
11
11
|
@offset = (offset || 0).to_i.clamp(0, Float::INFINITY)
|
12
|
+
@sort_by = sort_by
|
12
13
|
end
|
13
14
|
|
14
15
|
def records
|
15
|
-
@records ||=
|
16
|
+
@records ||= begin
|
17
|
+
res = @base_query.order(:id).limit(limit).offset(offset)
|
18
|
+
order_options = sort_by_options(res.klass)
|
19
|
+
res = res.reorder(order_options) if order_options.present?
|
20
|
+
res
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
def response
|
@@ -83,6 +89,19 @@ module ManageIQ
|
|
83
89
|
def count
|
84
90
|
@count ||= @base_query.count
|
85
91
|
end
|
92
|
+
|
93
|
+
def sort_by_options(model)
|
94
|
+
@sort_by_options ||= begin
|
95
|
+
Array(sort_by).collect do |selection|
|
96
|
+
sort_attr, sort_order = selection.split(':')
|
97
|
+
sort_order ||= "asc"
|
98
|
+
arel = model.arel_attribute(sort_attr)
|
99
|
+
arel = arel.asc if sort_order == "asc"
|
100
|
+
arel = arel.desc if sort_order == "desc"
|
101
|
+
arel
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
86
105
|
end
|
87
106
|
end
|
88
107
|
end
|
@@ -13,7 +13,7 @@ module ManageIQ
|
|
13
13
|
@resource_id = options[:resource_id]
|
14
14
|
@resource_name = options[:resource_name]
|
15
15
|
@share_info = []
|
16
|
-
@roles = RBAC::Roles.new("#{@app_name}-#{@resource_name}-#{@resource_id}")
|
16
|
+
@roles = RBAC::Roles.new("#{@app_name}-#{@resource_name}-#{@resource_id}", 'account')
|
17
17
|
end
|
18
18
|
|
19
19
|
def process
|
@@ -17,7 +17,7 @@ module ManageIQ
|
|
17
17
|
|
18
18
|
def process
|
19
19
|
validate_groups
|
20
|
-
@roles = RBAC::Roles.new("#{@app_name}-#{@resource_name}-")
|
20
|
+
@roles = RBAC::Roles.new("#{@app_name}-#{@resource_name}-", 'account')
|
21
21
|
@group_uuids.each { |uuid| manage_roles_for_group(uuid) }
|
22
22
|
self
|
23
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manageiq-api-common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ManageIQ Authors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_tenant
|
@@ -327,6 +327,7 @@ files:
|
|
327
327
|
- lib/manageiq/api/common/application_controller_mixins/openapi_enabled.rb
|
328
328
|
- lib/manageiq/api/common/application_controller_mixins/parameters.rb
|
329
329
|
- lib/manageiq/api/common/application_controller_mixins/request_body_validation.rb
|
330
|
+
- lib/manageiq/api/common/application_controller_mixins/request_parameter_validation.rb
|
330
331
|
- lib/manageiq/api/common/application_controller_mixins/request_path.rb
|
331
332
|
- lib/manageiq/api/common/engine.rb
|
332
333
|
- lib/manageiq/api/common/entitlement.rb
|
@@ -342,6 +343,7 @@ files:
|
|
342
343
|
- lib/manageiq/api/common/graphql/types/big_int.rb
|
343
344
|
- lib/manageiq/api/common/graphql/types/date_time.rb
|
344
345
|
- lib/manageiq/api/common/graphql/types/query_filter.rb
|
346
|
+
- lib/manageiq/api/common/graphql/types/query_sort_by.rb
|
345
347
|
- lib/manageiq/api/common/inflections.rb
|
346
348
|
- lib/manageiq/api/common/logging.rb
|
347
349
|
- lib/manageiq/api/common/metrics.rb
|