haveapi 0.24.0 → 0.25.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: 3aa75ace0c33e4332c2e01370c769d011a8b4bc1f143dcc72ff9a5019c55cf6c
4
- data.tar.gz: 86bce4af8c7d347bc11f6f3b840bc0d16ea4bac8d6bec827c1d6aea2f5a2c53f
3
+ metadata.gz: 3e3abf24d477cb53a7654a236f2daf3abadd8b153d3017ea159dbe1dd072fd2b
4
+ data.tar.gz: 406961707ce35f79c6ee6f2835697143f2b5a4e42e86f433949d08f98b546644
5
5
  SHA512:
6
- metadata.gz: bb2e3d9d6f1b554b96896b1d3d45b18ac07e9a4d0bf6ea98a505125d741414a41c973f37d3717cac128f1ba58a1fc645d490f4fa8881e1394f2c0f9a56df7d68
7
- data.tar.gz: 8af545bdde9b7535460a99da6999a85c79c482b85c08a82af984e3acccd42d27df1dabb235a1f876280b6dd20763462a98789b1c44da6918e5bbfedcf3d7f48f
6
+ metadata.gz: bdddd4eb49bc38b54c799b2cd57668f550a38212f1b735f1aad6238bb93f4a7d3b0b1bc52ff09055d0247afd70fa6fe156b41d7c99bc20317bc470d22ae9f744
7
+ data.tar.gz: 0120c81aa41cbc7a32d039fb4c645b2fa1ca510d91093c813e4e3b8802e69393e2641af63c99287fbb8b75f56021461e1c2eaf67351874f7ee8865195af7cac6
data/README.md CHANGED
@@ -138,7 +138,7 @@ module MyAPI
138
138
 
139
139
  # Execute action, return the list
140
140
  def exec
141
- query.limit(input[:limit]).offset(input[:offset])
141
+ with_pagination(query)
142
142
  end
143
143
  end
144
144
 
@@ -178,9 +178,9 @@ module MyAPI
178
178
  user = ::User.new(input)
179
179
 
180
180
  if user.save
181
- ok(user)
181
+ ok!(user)
182
182
  else
183
- error('save failed', user.errors.to_hash)
183
+ error!('save failed', user.errors.to_hash)
184
184
  end
185
185
  end
186
186
  end
data/haveapi.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.add_dependency 'activesupport', '>= 7.1'
18
18
  s.add_dependency 'github-markdown'
19
- s.add_dependency 'haveapi-client', '~> 0.24.0'
19
+ s.add_dependency 'haveapi-client', '~> 0.25.0'
20
20
  s.add_dependency 'json'
21
21
  s.add_dependency 'mail'
22
22
  s.add_dependency 'nesty', '~> 1.0'
@@ -323,7 +323,7 @@ module HaveAPI
323
323
  def validate!
324
324
  @params = validate
325
325
  rescue ValidationError => e
326
- error(e.message, e.to_hash)
326
+ error!(e.message, e.to_hash)
327
327
  end
328
328
 
329
329
  def authorized?(user)
@@ -379,11 +379,11 @@ module HaveAPI
379
379
  if tmp.empty?
380
380
  p e.message
381
381
  puts e.backtrace
382
- error('Server error occurred')
382
+ error!('Server error occurred')
383
383
  end
384
384
 
385
385
  unless tmp[:status]
386
- error(tmp[:message], {}, http_status: tmp[:http_status] || 500)
386
+ error!(tmp[:message], {}, http_status: tmp[:http_status] || 500)
387
387
  end
388
388
  end
389
389
 
@@ -555,7 +555,7 @@ module HaveAPI
555
555
  # @param ret [Hash] response
556
556
  # @param opts [Hash] options
557
557
  # @option opts [Integer] http_status HTTP status code sent to the client
558
- def ok(ret = {}, opts = {})
558
+ def ok!(ret = {}, opts = {})
559
559
  @http_status = opts[:http_status]
560
560
  throw(:return, ret)
561
561
  end
@@ -564,7 +564,7 @@ module HaveAPI
564
564
  # @param errs [Hash<Array>] parameter errors sent to the client
565
565
  # @param opts [Hash] options
566
566
  # @option opts [Integer] http_status HTTP status code sent to the client
567
- def error(msg, errs = {}, opts = {})
567
+ def error!(msg, errs = {}, opts = {})
568
568
  @message = msg
569
569
  @errors = errs
570
570
  @http_status = opts[:http_status]
@@ -11,11 +11,11 @@ module HaveAPI
11
11
  class ActionState
12
12
  # Return an array of objects representing actions that are pending completion.
13
13
  # @param [Object] user
14
- # @param [Integer] offset
14
+ # @param [Integer] from_id
15
15
  # @param [Integer] limit
16
16
  # @param [Symbol] order (:newest or :oldest)
17
17
  # @return [Array<ActionState>]
18
- def self.list_pending(user, offset, limit, order)
18
+ def self.list_pending(user, from_id, limit, order)
19
19
  raise NotImplementedError
20
20
  end
21
21
 
@@ -2,9 +2,9 @@ module HaveAPI::Actions
2
2
  module Paginable
3
3
  def self.included(action)
4
4
  action.input do
5
- integer :offset, label: 'Offset', desc: 'The offset of the first object',
6
- number: { min: 0 }
7
- integer :limit, label: 'Limit', desc: 'The number of objects to retrieve',
5
+ integer :from_id, label: 'From ID', desc: 'List objects with greater/lesser ID',
6
+ number: { min: 0 }
7
+ integer :limit, label: 'Limit', desc: 'Number of objects to retrieve',
8
8
  number: { min: 0 }
9
9
  end
10
10
  end
@@ -227,11 +227,11 @@ module HaveAPI::Authentication
227
227
  input:
228
228
  ), ActionResult.new)
229
229
  rescue HaveAPI::AuthenticationError => e
230
- error(e.message)
230
+ error!(e.message)
231
231
  end
232
232
 
233
233
  unless result.ok?
234
- error(result.error || 'invalid authentication credentials')
234
+ error!(result.error || 'invalid authentication credentials')
235
235
  end
236
236
 
237
237
  {
@@ -260,9 +260,9 @@ module HaveAPI::Authentication
260
260
  ), ActionResult.new)
261
261
 
262
262
  if result.ok?
263
- ok
263
+ ok!
264
264
  else
265
- error(result.error || 'revoke failed')
265
+ error!(result.error || 'revoke failed')
266
266
  end
267
267
  end
268
268
  end
@@ -290,7 +290,7 @@ module HaveAPI::Authentication
290
290
  if result.ok?
291
291
  { valid_to: result.valid_to }
292
292
  else
293
- error(result.error || 'renew failed')
293
+ error!(result.error || 'renew failed')
294
294
  end
295
295
  end
296
296
  end
@@ -324,11 +324,11 @@ module HaveAPI::Authentication
324
324
  token: input[:token]
325
325
  ), ActionResult.new)
326
326
  rescue HaveAPI::AuthenticationError => e
327
- error(e.message)
327
+ error!(e.message)
328
328
  end
329
329
 
330
330
  unless result.ok?
331
- error(result.error || 'authentication failed')
331
+ error!(result.error || 'authentication failed')
332
332
  end
333
333
 
334
334
  {
@@ -41,6 +41,47 @@ module HaveAPI::ModelAdapters
41
41
  end
42
42
  end
43
43
 
44
+ # Apply pagination on query in ascending order
45
+ # @param q [ActiveRecord::Relation] query to apply pagination on
46
+ def with_asc_pagination(q = nil)
47
+ ar_with_pagination(q, check: true) do |query, from_id|
48
+ query.where("`#{self.class.model.table_name}`.`#{self.class.model.primary_key}` > ?", from_id)
49
+ end
50
+ end
51
+
52
+ # Apply pagination on query in descending order
53
+ # @param q [ActiveRecord::Relation] query to apply pagination on
54
+ def with_desc_pagination(q = nil)
55
+ ar_with_pagination(q, check: true) do |query, from_id|
56
+ query.where("`#{self.class.model.table_name}`.`#{self.class.model.primary_key}` < ?", from_id)
57
+ end
58
+ end
59
+
60
+ alias with_pagination with_asc_pagination
61
+
62
+ # @param q [ActiveRecord::Relation] query to apply pagination on
63
+ # @param parameter [Symbol] input parameter used for pagination
64
+ # @param check [Boolean] raise if the model does not have a simple primary key
65
+ # @yieldparam q [ActiveRecord::Relation] query to apply pagination on
66
+ # @yieldparam parameter [any] value of the input parameter
67
+ def ar_with_pagination(q, parameter: :from_id, check: false)
68
+ pk = self.class.model.primary_key
69
+
70
+ if check && !pk.is_a?(String)
71
+ raise 'only simple primary key is supported, ' \
72
+ "#{self.class.model} has a composite primary key (#{pk.join(', ')})"
73
+ end
74
+
75
+ q ||= self.class.model.all
76
+
77
+ paginable = input[parameter]
78
+ limit = input[:limit]
79
+
80
+ q = yield(q, paginable) if paginable
81
+ q = q.limit(limit) if limit
82
+ q
83
+ end
84
+
44
85
  # Parse includes sent by the user and return them
45
86
  # in an array of symbols and hashes.
46
87
  def ar_parse_includes(raw)
@@ -154,6 +154,13 @@ module HaveAPI
154
154
  @params.detect { |p| p.name == name }.patch(changes)
155
155
  end
156
156
 
157
+ def remove(name)
158
+ i = @params.index { |p| p.name == name }
159
+ raise "Parameter #{name.inspect} not found" if i.nil?
160
+
161
+ @params.delete_at(i)
162
+ end
163
+
157
164
  # Action returns custom data.
158
165
  def custom(name, **kwargs, &block)
159
166
  add_param(name, apply(kwargs, type: Custom, clean: block))
@@ -63,7 +63,7 @@ module HaveAPI::Resources
63
63
  def exec
64
64
  actions = @context.server.action_state.list_pending(
65
65
  current_user,
66
- input[:offset],
66
+ input[:from_id],
67
67
  input[:limit],
68
68
  input[:order].to_sym
69
69
  )
@@ -106,7 +106,7 @@ module HaveAPI::Resources
106
106
  id: params[:action_state_id]
107
107
  )
108
108
 
109
- error('action state not found') unless state.valid?
109
+ error!('action state not found') unless state.valid?
110
110
 
111
111
  if state.finished? || (Time.now - t) >= input[:timeout]
112
112
  return state_to_hash(state)
@@ -145,7 +145,7 @@ module HaveAPI::Resources
145
145
 
146
146
  return state_to_hash(state) if state.valid?
147
147
 
148
- error('action state not found')
148
+ error!('action state not found')
149
149
  end
150
150
  end
151
151
 
@@ -164,7 +164,7 @@ module HaveAPI::Resources
164
164
  id: params[:action_state_id]
165
165
  )
166
166
 
167
- error('action state not found') unless state.valid?
167
+ error!('action state not found') unless state.valid?
168
168
 
169
169
  ret = state.cancel
170
170
 
@@ -172,13 +172,13 @@ module HaveAPI::Resources
172
172
  @state_id = ret
173
173
 
174
174
  elsif ret
175
- ok
175
+ ok!
176
176
 
177
177
  else
178
- error('cancellation failed')
178
+ error!('cancellation failed')
179
179
  end
180
180
  rescue RuntimeError, NotImplementedError => e
181
- error(e.message)
181
+ error!(e.message)
182
182
  end
183
183
 
184
184
  attr_reader :state_id
@@ -166,13 +166,19 @@ module HaveAPI
166
166
  ret += "<h5>#{name.to_s.capitalize}</h5>"
167
167
  ret += '<dl>'
168
168
  opts.each do |k, v|
169
- ret += "<dt>#{k}</dt><dd>#{v}</dd>"
169
+ ret += "<dt>#{k}</dt><dd>#{escape_html(v.to_s)}</dd>"
170
170
  end
171
171
  ret += '</dl>'
172
172
  end
173
173
 
174
174
  ret
175
175
  end
176
+
177
+ def escape_html(v)
178
+ return '' if v.nil?
179
+
180
+ CGI.escapeHTML(v.to_s)
181
+ end
176
182
  end
177
183
 
178
184
  def initialize(module_name = HaveAPI.module_name)
@@ -1,4 +1,4 @@
1
1
  module HaveAPI
2
2
  PROTOCOL_VERSION = '2.0'.freeze
3
- VERSION = '0.24.0'.freeze
3
+ VERSION = '0.25.0'.freeze
4
4
  end
@@ -54,8 +54,8 @@
54
54
  <td><%= info[:required] ? 'yes' : 'no' %></td>
55
55
  <td><%= format_param_type(info) %></td>
56
56
  <td><%= format_validators(info[:validators]) %></td>
57
- <td><%= info[:default] == :_nil ? '' : info[:default] %></td>
58
- <td><%= info[:description] %></td>
57
+ <td><%= info[:default] == :_nil ? '' : escape_html(info[:default]) %></td>
58
+ <td><%= escape_html(info[:description]) %></td>
59
59
  </tr>
60
60
  <% end %>
61
61
  </table>
@@ -86,18 +86,13 @@
86
86
  <td><%= info[:label] %></td>
87
87
  <td><%= param %></td>
88
88
  <td><%= format_param_type(info) %></td>
89
- <td><%= info[:description] %></td>
89
+ <td><%= escape_html(info[:description]) %></td>
90
90
  </tr>
91
91
  <% end %>
92
92
  </table>
93
93
  <% end %>
94
94
  </div>
95
95
 
96
- <div class="action-self-description">
97
- <h4>Self-description</h4>
98
- <pre><code><%= JSON.pretty_generate(info) %></code></pre>
99
- </div>
100
-
101
96
  <% unless info[:examples].empty? %>
102
97
  <h4>Examples</h4>
103
98
  <% info[:examples].each_with_index do |example, i| %>
@@ -111,33 +111,5 @@ nojsTabs({
111
111
 
112
112
  event.preventDefault();
113
113
  });
114
-
115
- // Show/hide button for help messages
116
- $('.action .action-self-description').each(function(i, el){
117
- // replace text by show/hide button
118
- var div = $(el);
119
- var pre = div.find('pre');
120
- var h4 = div.find('h4');
121
- h4.text('');
122
-
123
- h4.append(
124
- $('<button>')
125
- .attr('type', 'button')
126
- .addClass('btn btn-primary btn-sm')
127
- .text('Show self-description')
128
- .click(function(event) {
129
- var button = $(this);
130
- button.toggleClass('active');
131
- pre.toggle('fast');
132
-
133
- if(button.hasClass('active'))
134
- button.text('Hide self-description');
135
- else
136
- button.text('Show self-description');
137
- })
138
- );
139
-
140
- $(el).find('pre').hide();
141
- });
142
114
  });
143
115
  </script>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haveapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Skokan
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.24.0
47
+ version: 0.25.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.24.0
54
+ version: 0.25.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: json
57
57
  requirement: !ruby/object:Gem::Requirement