manageiq-api-common 2.0.1 → 2.1.0

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: 505d9b26de12a65214f045cba58f0cd0d3f03f24b52e34c9f91c93438107593a
4
- data.tar.gz: 93742f14fcc2493740e3b85b42cbcd8f3bc2e06b0b1e35ee3e306dc5eacb6564
3
+ metadata.gz: 46a97632c285025bf8e8f2d7204409a6afb43b29b2781a72dcceba180770622e
4
+ data.tar.gz: a9574eb959db384c326bcc9b591a3a462e7991f1be340d1d8747712b9e5eea2f
5
5
  SHA512:
6
- metadata.gz: 46a55bf1c465a7de8ef16d7245f182dc60b1e14a6a650ac4f882f894889df8fe481e160c76a8701b3882c2abd72656f1bd38d0cdadf1467dff70d4f6e29e9206
7
- data.tar.gz: 90ece62ebe786c71c3bc94d20d6bbbacced40abe5168ab9aabf93d628289ab5ef47fd6a982958dd228c7c72fd90dc9dff8fbba4ac8173767d15aa452fc38bbb8
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, 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}"
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 ||= @base_query.order(:id).limit(limit).offset(offset)
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
@@ -1,7 +1,7 @@
1
1
  module ManageIQ
2
2
  module API
3
3
  module Common
4
- VERSION = "2.0.1".freeze
4
+ VERSION = "2.1.0".freeze
5
5
  end
6
6
  end
7
7
  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.1
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-10-23 00:00:00.000000000 Z
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