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 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