haveapi 0.24.0 → 0.26.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 +3 -3
- data/haveapi.gemspec +1 -1
- data/lib/haveapi/action.rb +5 -12
- data/lib/haveapi/action_state.rb +2 -2
- data/lib/haveapi/actions/paginable.rb +3 -3
- data/lib/haveapi/authentication/token/provider.rb +7 -7
- data/lib/haveapi/model_adapters/active_record.rb +41 -0
- data/lib/haveapi/params.rb +7 -0
- data/lib/haveapi/resources/action_state.rb +7 -7
- data/lib/haveapi/server.rb +7 -1
- data/lib/haveapi/version.rb +1 -1
- data/lib/haveapi/views/version_page/resource_body.erb +3 -8
- data/lib/haveapi/views/version_page.erb +0 -28
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a2568eccc37711467dbd932eb6bb9c8fdf037dd82aca94f1d6791f563512f98
|
4
|
+
data.tar.gz: 5ef77a76b6f9c2457939542b650a3a73c0c67527845fca252d5ab80d61e4a390
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c8903f4f81aaf485c22e8d056a70d691cda21a99b93b14ba9e4ebee3c2f518c2a08dfa5e0a3cc5b01057b9d94c3837bf3c0eee623c35ad2e8a37cc86ae93cd
|
7
|
+
data.tar.gz: 2b45b84c7e020ad680c7a6357bf5acc0893470a23cad01f830a4934bb61c33d8807b25e751f11a1fa41b631380f7b784b345939034ba897b07b77af475777f1c
|
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
|
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.
|
19
|
+
s.add_dependency 'haveapi-client', '~> 0.26.0'
|
20
20
|
s.add_dependency 'json'
|
21
21
|
s.add_dependency 'mail'
|
22
22
|
s.add_dependency 'nesty', '~> 1.0'
|
data/lib/haveapi/action.rb
CHANGED
@@ -197,13 +197,6 @@ module HaveAPI
|
|
197
197
|
|
198
198
|
def build_route(prefix)
|
199
199
|
route = @route || action_name.underscore
|
200
|
-
if @route
|
201
|
-
@route
|
202
|
-
elsif action_name
|
203
|
-
action_name.to_s.demodulize.underscore
|
204
|
-
else
|
205
|
-
to_s.demodulize.underscore
|
206
|
-
end
|
207
200
|
|
208
201
|
if !route.is_a?(String) && route.respond_to?(:call)
|
209
202
|
route = route.call(resource)
|
@@ -323,7 +316,7 @@ module HaveAPI
|
|
323
316
|
def validate!
|
324
317
|
@params = validate
|
325
318
|
rescue ValidationError => e
|
326
|
-
error(e.message, e.to_hash)
|
319
|
+
error!(e.message, e.to_hash)
|
327
320
|
end
|
328
321
|
|
329
322
|
def authorized?(user)
|
@@ -379,11 +372,11 @@ module HaveAPI
|
|
379
372
|
if tmp.empty?
|
380
373
|
p e.message
|
381
374
|
puts e.backtrace
|
382
|
-
error('Server error occurred')
|
375
|
+
error!('Server error occurred')
|
383
376
|
end
|
384
377
|
|
385
378
|
unless tmp[:status]
|
386
|
-
error(tmp[:message], {}, http_status: tmp[:http_status] || 500)
|
379
|
+
error!(tmp[:message], {}, http_status: tmp[:http_status] || 500)
|
387
380
|
end
|
388
381
|
end
|
389
382
|
|
@@ -555,7 +548,7 @@ module HaveAPI
|
|
555
548
|
# @param ret [Hash] response
|
556
549
|
# @param opts [Hash] options
|
557
550
|
# @option opts [Integer] http_status HTTP status code sent to the client
|
558
|
-
def ok(ret = {}, opts = {})
|
551
|
+
def ok!(ret = {}, opts = {})
|
559
552
|
@http_status = opts[:http_status]
|
560
553
|
throw(:return, ret)
|
561
554
|
end
|
@@ -564,7 +557,7 @@ module HaveAPI
|
|
564
557
|
# @param errs [Hash<Array>] parameter errors sent to the client
|
565
558
|
# @param opts [Hash] options
|
566
559
|
# @option opts [Integer] http_status HTTP status code sent to the client
|
567
|
-
def error(msg, errs = {}, opts = {})
|
560
|
+
def error!(msg, errs = {}, opts = {})
|
568
561
|
@message = msg
|
569
562
|
@errors = errs
|
570
563
|
@http_status = opts[:http_status]
|
data/lib/haveapi/action_state.rb
CHANGED
@@ -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]
|
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,
|
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 :
|
6
|
-
|
7
|
-
integer :limit, label: 'Limit', desc: '
|
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)
|
data/lib/haveapi/params.rb
CHANGED
@@ -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[:
|
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
|
data/lib/haveapi/server.rb
CHANGED
@@ -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)
|
data/lib/haveapi/version.rb
CHANGED
@@ -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.
|
4
|
+
version: 0.26.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.
|
47
|
+
version: 0.26.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.
|
54
|
+
version: 0.26.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -343,7 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
343
343
|
- !ruby/object:Gem::Version
|
344
344
|
version: '0'
|
345
345
|
requirements: []
|
346
|
-
rubygems_version: 3.5.
|
346
|
+
rubygems_version: 3.5.22
|
347
347
|
signing_key:
|
348
348
|
specification_version: 4
|
349
349
|
summary: Framework for creating self-describing APIs
|