haveapi 0.29.1 → 0.29.3
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 +21 -0
- data/haveapi.gemspec +1 -1
- data/lib/haveapi/authentication/basic/provider.rb +1 -2
- data/lib/haveapi/authentication/chain.rb +1 -1
- data/lib/haveapi/authentication/oauth2/provider.rb +1 -17
- data/lib/haveapi/authentication/token/provider.rb +9 -1
- data/lib/haveapi/locales/cs.yml +100 -63
- data/lib/haveapi/locales/en.yml +103 -67
- data/lib/haveapi/parameters/metadata_i18n.rb +80 -3
- data/lib/haveapi/parameters/typed.rb +5 -1
- data/lib/haveapi/resources/action_state.rb +6 -4
- data/lib/haveapi/version.rb +1 -1
- data/spec/action/runtime_spec.rb +1 -1
- data/spec/action/validation_http_status_spec.rb +2 -2
- data/spec/action_state_spec.rb +4 -4
- data/spec/authentication/basic_spec.rb +3 -3
- data/spec/authentication/oauth2_spec.rb +3 -1
- data/spec/authentication/token_spec.rb +8 -0
- data/spec/extensions/exception_mailer_spec.rb +2 -2
- data/spec/i18n_spec.rb +88 -9
- data/spec/model_adapters/active_record_spec.rb +8 -8
- data/spec/params_spec.rb +18 -0
- data/spec/server/integration_spec.rb +5 -5
- metadata +3 -3
data/lib/haveapi/locales/en.yml
CHANGED
|
@@ -5,33 +5,57 @@
|
|
|
5
5
|
en:
|
|
6
6
|
haveapi:
|
|
7
7
|
action_state:
|
|
8
|
-
cancellation_failed: cancellation failed
|
|
9
|
-
not_found:
|
|
10
|
-
timeout_max: timeout
|
|
8
|
+
cancellation_failed: Action cancellation failed
|
|
9
|
+
not_found: Action state not found
|
|
10
|
+
timeout_max: timeout must be at most %{max}
|
|
11
11
|
authentication:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
basic:
|
|
13
|
+
description: |-
|
|
14
|
+
Authentication using HTTP Basic. The username and password are passed in an HTTP header.
|
|
15
|
+
This method must not be used from web browsers.
|
|
16
|
+
failed: Authentication failed
|
|
17
|
+
invalid_credentials: Invalid authentication credentials
|
|
18
|
+
multiple_oauth2_tokens: Multiple OAuth2 tokens were provided
|
|
19
|
+
multiple_tokens: Multiple authentication tokens were provided
|
|
20
|
+
oauth2:
|
|
21
|
+
description: |-
|
|
22
|
+
OAuth2 authorization provider.
|
|
23
|
+
HaveAPI clients have limited OAuth2 support, but the API can be used as an authentication source and OAuth2 tokens can be used to access it. HaveAPI partially implements RFC 6749: authorization response type "code" and token grant types "authorization_code" and "refresh_token". Other response and grant types are not supported at this time. The access token can be passed as a bearer token according to RFC 6750, or using a custom HTTP header when the Authorization header is not practical.
|
|
24
|
+
Access and refresh tokens can be revoked according to RFC 7009.
|
|
25
|
+
renew_failed: Token renewal failed
|
|
26
|
+
required: This action requires authentication
|
|
27
|
+
revoke_failed: Token revocation failed
|
|
28
|
+
token:
|
|
29
|
+
actions:
|
|
30
|
+
renew:
|
|
31
|
+
description: Renew the current authentication token
|
|
32
|
+
request:
|
|
33
|
+
description: Request an authentication token
|
|
34
|
+
revoke:
|
|
35
|
+
description: Revoke the current authentication token
|
|
36
|
+
description: The client authenticates with credentials, usually a username
|
|
37
|
+
and password, and receives a token. From that point on, the credentials
|
|
38
|
+
can be forgotten and the token is used instead. Tokens can have different
|
|
39
|
+
lifetimes and can be renewed or revoked. The token is passed either in an
|
|
40
|
+
HTTP header or as a query parameter.
|
|
41
|
+
resource:
|
|
42
|
+
description: Manage authentication tokens
|
|
43
|
+
token_required: This action requires token authentication
|
|
20
44
|
authorization:
|
|
21
45
|
insufficient_permissions: Access denied. Insufficient permissions.
|
|
22
46
|
errors:
|
|
23
47
|
action_not_found: Action not found
|
|
24
|
-
bad_accept_header:
|
|
25
|
-
bad_json_syntax:
|
|
26
|
-
json_body_object: JSON body must be an object
|
|
27
|
-
server_error:
|
|
28
|
-
unsupported_content_type: Unsupported Content-Type
|
|
48
|
+
bad_accept_header: Invalid Accept header
|
|
49
|
+
bad_json_syntax: Invalid JSON syntax
|
|
50
|
+
json_body_object: The JSON request body must be an object
|
|
51
|
+
server_error: A server error occurred
|
|
52
|
+
unsupported_content_type: Unsupported Content-Type header
|
|
29
53
|
pagination:
|
|
30
|
-
limit_max: limit
|
|
54
|
+
limit_max: limit must be at most %{max}
|
|
31
55
|
parameters:
|
|
32
56
|
action_state:
|
|
33
57
|
can_cancel:
|
|
34
|
-
description: When true,
|
|
58
|
+
description: When true, this action can be cancelled
|
|
35
59
|
label: Can cancel
|
|
36
60
|
created_at:
|
|
37
61
|
label: Created at
|
|
@@ -43,60 +67,59 @@ en:
|
|
|
43
67
|
label: Label
|
|
44
68
|
poll:
|
|
45
69
|
current:
|
|
46
|
-
description: progress to
|
|
70
|
+
description: Current progress value to compare when update_in is set
|
|
47
71
|
status:
|
|
48
|
-
description:
|
|
72
|
+
description: Status value to compare when update_in is set
|
|
49
73
|
timeout:
|
|
50
|
-
description: in seconds
|
|
74
|
+
description: Timeout in seconds
|
|
51
75
|
label: Timeout
|
|
52
76
|
total:
|
|
53
|
-
description: progress to
|
|
77
|
+
description: Total progress value to compare when update_in is set
|
|
54
78
|
update_in:
|
|
55
|
-
description:
|
|
56
|
-
|
|
57
|
-
label:
|
|
79
|
+
description: Return early when status, current, or total changes; the
|
|
80
|
+
value is passed to API-specific polling implementations
|
|
81
|
+
label: Update in
|
|
58
82
|
status:
|
|
59
|
-
description:
|
|
83
|
+
description: Whether the action is proceeding successfully or has failed
|
|
60
84
|
label: Status
|
|
61
85
|
total:
|
|
62
|
-
description: The action is finished when current
|
|
86
|
+
description: The action is finished when current reaches total
|
|
63
87
|
label: Total
|
|
64
88
|
unit:
|
|
65
89
|
description: Unit of current and total
|
|
66
90
|
label: Unit
|
|
67
91
|
updated_at:
|
|
68
|
-
description: When
|
|
92
|
+
description: When the progress was last updated
|
|
69
93
|
label: Updated at
|
|
70
94
|
action_state_id:
|
|
71
|
-
description:
|
|
72
|
-
|
|
95
|
+
description: |-
|
|
96
|
+
ID of the ActionState object for state polling.
|
|
97
|
+
When null, the action is not blocking for the current invocation.
|
|
73
98
|
label: Action state ID
|
|
74
99
|
active_record:
|
|
75
100
|
includes:
|
|
76
|
-
description:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
To resolve further associations of node, use e.g. 'user,node__location',
|
|
81
|
-
to go even deeper, use e.g. 'user,node__location__environment'.
|
|
101
|
+
description: A comma-separated list of associated resource names. Nested
|
|
102
|
+
associations are declared with '__' between resource names. For example,
|
|
103
|
+
'user,node' includes these two associations. To include further associations
|
|
104
|
+
of node, use e.g. 'user,node__location'; to go even deeper, use e.g. 'user,node__location__environment'.
|
|
82
105
|
label: Included associations
|
|
83
106
|
path_params:
|
|
84
|
-
description: An array of parameters needed to
|
|
107
|
+
description: An array of parameters needed to build the URL for this object
|
|
85
108
|
label: URL parameters
|
|
86
109
|
resolved:
|
|
87
|
-
description: True if the association
|
|
110
|
+
description: True if the association has been loaded
|
|
88
111
|
label: Resolved
|
|
89
112
|
authentication:
|
|
90
113
|
token:
|
|
91
114
|
interval:
|
|
92
|
-
description: How long
|
|
115
|
+
description: How long the requested token will be valid, in seconds.
|
|
93
116
|
label: Interval
|
|
94
117
|
lifetime:
|
|
95
118
|
description: |-
|
|
96
|
-
fixed - the token has a fixed validity period
|
|
97
|
-
renewable_manual - the token can be renewed, but
|
|
98
|
-
renewable_auto - the token is renewed automatically to now+interval
|
|
99
|
-
permanent - the token
|
|
119
|
+
fixed - the token has a fixed validity period and cannot be renewed
|
|
120
|
+
renewable_manual - the token can be renewed, but only manually using the renew action
|
|
121
|
+
renewable_auto - the token is renewed automatically to now + interval whenever it is used
|
|
122
|
+
permanent - the token is valid forever unless deleted
|
|
100
123
|
label: Lifetime
|
|
101
124
|
password:
|
|
102
125
|
label: Password
|
|
@@ -106,39 +129,52 @@ en:
|
|
|
106
129
|
label: User
|
|
107
130
|
default:
|
|
108
131
|
count:
|
|
109
|
-
label: Return
|
|
132
|
+
label: Return total count
|
|
110
133
|
total_count:
|
|
111
|
-
label: Total count
|
|
134
|
+
label: Total item count
|
|
112
135
|
metadata:
|
|
113
136
|
'no':
|
|
114
137
|
label: Disable metadata
|
|
115
138
|
paginable:
|
|
116
139
|
from_id:
|
|
117
|
-
description: List objects with greater
|
|
140
|
+
description: List objects with IDs greater or lower than this value
|
|
118
141
|
label: From ID
|
|
119
142
|
limit:
|
|
120
143
|
description: Number of objects to retrieve
|
|
121
144
|
label: Limit
|
|
145
|
+
resources:
|
|
146
|
+
action_state:
|
|
147
|
+
actions:
|
|
148
|
+
cancel:
|
|
149
|
+
description: Cancel a pending action
|
|
150
|
+
index:
|
|
151
|
+
description: List pending action states
|
|
152
|
+
poll:
|
|
153
|
+
description: Return when the action is completed, its progress changes,
|
|
154
|
+
or a timeout occurs
|
|
155
|
+
show:
|
|
156
|
+
description: Show the state of a pending action
|
|
157
|
+
description: Browse states of blocking actions
|
|
122
158
|
types:
|
|
123
|
-
invalid_boolean: not a valid boolean %{value}
|
|
124
|
-
invalid_datetime: not in ISO 8601 format '%{value}'
|
|
125
|
-
invalid_float: not a valid float %{value}
|
|
126
|
-
invalid_integer: not a valid integer %{value}
|
|
127
|
-
invalid_string: not a valid string %{value}
|
|
159
|
+
invalid_boolean: 'not a valid boolean: %{value}'
|
|
160
|
+
invalid_datetime: 'not in ISO 8601 format: ''%{value}'''
|
|
161
|
+
invalid_float: 'not a valid float: %{value}'
|
|
162
|
+
invalid_integer: 'not a valid integer: %{value}'
|
|
163
|
+
invalid_string: 'not a valid string: %{value}'
|
|
128
164
|
validation:
|
|
129
165
|
cannot_be_null: cannot be null
|
|
130
166
|
includes_only_strings: includes must contain only strings
|
|
131
167
|
includes_string_or_array: includes must be a string or array
|
|
132
|
-
input_parameters_not_valid: input parameters not valid
|
|
133
|
-
invalid_id: not a valid
|
|
168
|
+
input_parameters_not_valid: input parameters are not valid
|
|
169
|
+
invalid_id: 'not a valid ID: %{value}'
|
|
134
170
|
invalid_input_layout: invalid input layout
|
|
135
171
|
invalid_path_parameter_encoding: invalid path parameter encoding
|
|
136
172
|
invalid_string_encoding: invalid string encoding
|
|
137
|
-
required_parameter_missing: required parameter missing
|
|
173
|
+
required_parameter_missing: required parameter is missing
|
|
138
174
|
resource_not_found: resource not found
|
|
139
175
|
validators:
|
|
140
176
|
acceptance:
|
|
141
|
-
accepted:
|
|
177
|
+
accepted: must be %{value}
|
|
142
178
|
confirmation:
|
|
143
179
|
different: must be different from %{parameter}
|
|
144
180
|
same: must be the same as %{parameter}
|
|
@@ -149,20 +185,20 @@ en:
|
|
|
149
185
|
inclusion:
|
|
150
186
|
included: "%{value} cannot be used"
|
|
151
187
|
length:
|
|
152
|
-
equals: length
|
|
153
|
-
max: length
|
|
154
|
-
min: length
|
|
155
|
-
range: length
|
|
188
|
+
equals: length must be %{equals}
|
|
189
|
+
max: length must be at most %{max}
|
|
190
|
+
min: length must be at least %{min}
|
|
191
|
+
range: length must be between %{min} and %{max}
|
|
156
192
|
numericality:
|
|
157
193
|
composite: "%{requirements}"
|
|
158
|
-
even: even
|
|
159
|
-
max:
|
|
160
|
-
min:
|
|
161
|
-
mod:
|
|
162
|
-
number:
|
|
163
|
-
odd: odd
|
|
164
|
-
range:
|
|
165
|
-
step: in steps of %{step}
|
|
194
|
+
even: must be even
|
|
195
|
+
max: must be at most %{max}
|
|
196
|
+
min: must be at least %{min}
|
|
197
|
+
mod: remainder after division by %{mod} must be zero
|
|
198
|
+
number: must be a number
|
|
199
|
+
odd: must be odd
|
|
200
|
+
range: must be between %{min} and %{max}
|
|
201
|
+
step: must be in steps of %{step}
|
|
166
202
|
presence:
|
|
167
203
|
non_empty: must be present and non-empty
|
|
168
204
|
present: must be present
|
|
@@ -14,7 +14,7 @@ module HaveAPI::Parameters
|
|
|
14
14
|
keys:,
|
|
15
15
|
value:
|
|
16
16
|
}
|
|
17
|
-
end
|
|
17
|
+
end + choice_i18n_catalog_items(context, i18n_path)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
private
|
|
@@ -27,6 +27,17 @@ module HaveAPI::Parameters
|
|
|
27
27
|
localized_metadata(context, i18n_path, :description, @desc)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def localized_validators(context, i18n_path, validators)
|
|
31
|
+
include_validator = validators[:include]
|
|
32
|
+
return validators unless include_validator && include_validator.has_key?(:values)
|
|
33
|
+
|
|
34
|
+
values = include_validator.fetch(:values)
|
|
35
|
+
localized_values = localized_choice_values(context, i18n_path, values)
|
|
36
|
+
return validators if localized_values.equal?(values)
|
|
37
|
+
|
|
38
|
+
validators.merge(include: include_validator.merge(values: localized_values))
|
|
39
|
+
end
|
|
40
|
+
|
|
30
41
|
def localized_metadata(context, i18n_path, kind, fallback)
|
|
31
42
|
keys = metadata_i18n_keys(context, i18n_path, kind, fallback)
|
|
32
43
|
default = HaveAPI.localize(fallback)
|
|
@@ -61,6 +72,74 @@ module HaveAPI::Parameters
|
|
|
61
72
|
[exact_key, *metadata_i18n_default_keys(context, i18n_path, kind, scope)].uniq
|
|
62
73
|
end
|
|
63
74
|
|
|
75
|
+
def localized_choice_values(context, i18n_path, values)
|
|
76
|
+
case values
|
|
77
|
+
when ::Hash
|
|
78
|
+
values.to_h do |value, label|
|
|
79
|
+
[
|
|
80
|
+
value,
|
|
81
|
+
localized_metadata(context, i18n_path, choice_i18n_kind(value), label)
|
|
82
|
+
]
|
|
83
|
+
end
|
|
84
|
+
when ::Array
|
|
85
|
+
localized = values.to_h do |value|
|
|
86
|
+
label = localized_metadata(
|
|
87
|
+
context,
|
|
88
|
+
i18n_path,
|
|
89
|
+
choice_i18n_kind(value),
|
|
90
|
+
value.to_s
|
|
91
|
+
)
|
|
92
|
+
[value, label]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
localized.any? { |value, label| label.to_s != value.to_s } ? localized : values
|
|
96
|
+
else
|
|
97
|
+
values
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def choice_i18n_catalog_items(context, i18n_path)
|
|
102
|
+
values = choice_i18n_values
|
|
103
|
+
return [] unless values
|
|
104
|
+
|
|
105
|
+
choice_i18n_fallbacks(values).filter_map do |value, fallback|
|
|
106
|
+
keys = metadata_i18n_keys(context, i18n_path, choice_i18n_kind(value), fallback)
|
|
107
|
+
label = HaveAPI.localize(fallback).to_s.strip
|
|
108
|
+
|
|
109
|
+
next if keys.empty? || label.empty?
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
param: HaveAPI::Params.i18n_segment(@name),
|
|
113
|
+
kind: metadata_i18n_key_suffix(choice_i18n_kind(value)),
|
|
114
|
+
keys:,
|
|
115
|
+
value: label
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def choice_i18n_values
|
|
121
|
+
metadata_i18n_choice_values
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def metadata_i18n_choice_values
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def choice_i18n_fallbacks(values)
|
|
129
|
+
case values
|
|
130
|
+
when ::Hash
|
|
131
|
+
values
|
|
132
|
+
when ::Array
|
|
133
|
+
values.to_h { |value| [value, value.to_s] }
|
|
134
|
+
else
|
|
135
|
+
{}
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def choice_i18n_kind(value)
|
|
140
|
+
"choices.#{HaveAPI::Params.i18n_segment(value)}.label"
|
|
141
|
+
end
|
|
142
|
+
|
|
64
143
|
def metadata_i18n_fallback(kind)
|
|
65
144
|
case kind
|
|
66
145
|
when :label
|
|
@@ -78,8 +157,6 @@ module HaveAPI::Parameters
|
|
|
78
157
|
@label_key
|
|
79
158
|
when :description
|
|
80
159
|
@desc_key
|
|
81
|
-
else
|
|
82
|
-
raise ArgumentError, "unsupported parameter metadata kind #{kind.inspect}"
|
|
83
160
|
end
|
|
84
161
|
end
|
|
85
162
|
|
|
@@ -62,7 +62,7 @@ module HaveAPI::Parameters
|
|
|
62
62
|
label: localized_label(context, i18n_path),
|
|
63
63
|
description: localized_description(context, i18n_path),
|
|
64
64
|
type: @type ? @type.to_s : String.to_s,
|
|
65
|
-
validators: @validators ? @validators.describe : {},
|
|
65
|
+
validators: @validators ? localized_validators(context, i18n_path, @validators.describe) : {},
|
|
66
66
|
default: @default,
|
|
67
67
|
protected: @protected || false
|
|
68
68
|
}
|
|
@@ -167,6 +167,10 @@ module HaveAPI::Parameters
|
|
|
167
167
|
@type == Custom
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
+
def metadata_i18n_choice_values
|
|
171
|
+
@validators&.describe&.dig(:include, :values)
|
|
172
|
+
end
|
|
173
|
+
|
|
170
174
|
def normalize_custom_keys(value)
|
|
171
175
|
case value
|
|
172
176
|
when ::Hash
|
|
@@ -2,7 +2,7 @@ require 'haveapi/resource'
|
|
|
2
2
|
|
|
3
3
|
module HaveAPI::Resources
|
|
4
4
|
class ActionState < HaveAPI::Resource
|
|
5
|
-
desc '
|
|
5
|
+
desc HaveAPI.message('haveapi.resources.action_state.description')
|
|
6
6
|
auth false
|
|
7
7
|
version :all
|
|
8
8
|
|
|
@@ -54,7 +54,7 @@ module HaveAPI::Resources
|
|
|
54
54
|
class Index < HaveAPI::Actions::Default::Index
|
|
55
55
|
include Mixin
|
|
56
56
|
|
|
57
|
-
desc '
|
|
57
|
+
desc HaveAPI.message('haveapi.resources.action_state.actions.index.description')
|
|
58
58
|
|
|
59
59
|
input(:hash) do
|
|
60
60
|
string :order, choices: %w[newest oldest], default: 'newest', fill: true
|
|
@@ -85,7 +85,7 @@ module HaveAPI::Resources
|
|
|
85
85
|
|
|
86
86
|
MAX_TIMEOUT = 30
|
|
87
87
|
|
|
88
|
-
desc '
|
|
88
|
+
desc HaveAPI.message('haveapi.resources.action_state.actions.poll.description')
|
|
89
89
|
http_method :get
|
|
90
90
|
route '{%{resource}_id}/poll'
|
|
91
91
|
|
|
@@ -157,7 +157,7 @@ module HaveAPI::Resources
|
|
|
157
157
|
class Show < HaveAPI::Actions::Default::Show
|
|
158
158
|
include Mixin
|
|
159
159
|
|
|
160
|
-
desc '
|
|
160
|
+
desc HaveAPI.message('haveapi.resources.action_state.actions.show.description')
|
|
161
161
|
|
|
162
162
|
output(:hash) do
|
|
163
163
|
use :all
|
|
@@ -178,6 +178,8 @@ module HaveAPI::Resources
|
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
class Cancel < HaveAPI::Action
|
|
181
|
+
desc HaveAPI.message('haveapi.resources.action_state.actions.cancel.description')
|
|
182
|
+
|
|
181
183
|
http_method :post
|
|
182
184
|
route '{%{resource}_id}/cancel'
|
|
183
185
|
blocking true
|
data/lib/haveapi/version.rb
CHANGED
data/spec/action/runtime_spec.rb
CHANGED
|
@@ -638,7 +638,7 @@ describe HaveAPI::Action do
|
|
|
638
638
|
|
|
639
639
|
expect(last_response.status).to eq(200)
|
|
640
640
|
expect(api_response).not_to be_ok
|
|
641
|
-
expect(api_response.errors[:confirmed]).to include('required parameter missing')
|
|
641
|
+
expect(api_response.errors[:confirmed]).to include('required parameter is missing')
|
|
642
642
|
|
|
643
643
|
call_api([:Test], :batch, { tests: [{ label: 'one' }], _meta: { confirmed: 'maybe' } })
|
|
644
644
|
|
|
@@ -33,7 +33,7 @@ describe HaveAPI::Action do
|
|
|
33
33
|
|
|
34
34
|
expect(last_response.status).to eq(200)
|
|
35
35
|
expect(api_response).not_to be_ok
|
|
36
|
-
expect(api_response.errors[:name]).to include('required parameter missing')
|
|
36
|
+
expect(api_response.errors[:name]).to include('required parameter is missing')
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -69,7 +69,7 @@ describe HaveAPI::Action do
|
|
|
69
69
|
|
|
70
70
|
expect(last_response.status).to eq(400)
|
|
71
71
|
expect(api_response).not_to be_ok
|
|
72
|
-
expect(api_response.errors[:name]).to include('required parameter missing')
|
|
72
|
+
expect(api_response.errors[:name]).to include('required parameter is missing')
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
end
|
data/spec/action_state_spec.rb
CHANGED
|
@@ -184,7 +184,7 @@ describe HaveAPI::Resources::ActionState do
|
|
|
184
184
|
get_action '/v1/action_states/999'
|
|
185
185
|
|
|
186
186
|
expect(api_response).not_to be_ok
|
|
187
|
-
expect(api_response.message).to eq('
|
|
187
|
+
expect(api_response.message).to eq('Action state not found')
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
it 'poll returns immediately if finished' do
|
|
@@ -227,7 +227,7 @@ describe HaveAPI::Resources::ActionState do
|
|
|
227
227
|
|
|
228
228
|
expect(last_response.status).to eq(200)
|
|
229
229
|
expect(api_response).not_to be_ok
|
|
230
|
-
expect(api_response.errors[:timeout].first).to include('
|
|
230
|
+
expect(api_response.errors[:timeout].first).to include('between 0 and 30')
|
|
231
231
|
end
|
|
232
232
|
|
|
233
233
|
it 'poll returns immediately when update_in check mismatches' do
|
|
@@ -274,7 +274,7 @@ describe HaveAPI::Resources::ActionState do
|
|
|
274
274
|
get_action '/v1/action_states/999/poll', action_state: { timeout: 0 }
|
|
275
275
|
|
|
276
276
|
expect(api_response).not_to be_ok
|
|
277
|
-
expect(api_response.message).to eq('
|
|
277
|
+
expect(api_response.message).to eq('Action state not found')
|
|
278
278
|
end
|
|
279
279
|
|
|
280
280
|
it 'cancel returns ok for true' do
|
|
@@ -303,7 +303,7 @@ describe HaveAPI::Resources::ActionState do
|
|
|
303
303
|
call_api(:post, '/v1/action_states/1/cancel', {})
|
|
304
304
|
|
|
305
305
|
expect(api_response).not_to be_ok
|
|
306
|
-
expect(api_response.message).to eq('cancellation failed')
|
|
306
|
+
expect(api_response.message).to eq('Action cancellation failed')
|
|
307
307
|
end
|
|
308
308
|
|
|
309
309
|
it 'cancel returns error for NotImplementedError' do
|
|
@@ -73,7 +73,7 @@ describe HaveAPI::Authentication::Basic::Provider do
|
|
|
73
73
|
expect(last_response.headers['www-authenticate']).to include('Basic realm=')
|
|
74
74
|
|
|
75
75
|
expect(api_response).to be_failed
|
|
76
|
-
expect(api_response.message).to
|
|
76
|
+
expect(api_response.message).to eq('This action requires authentication')
|
|
77
77
|
expect(seen_users.last).to be_nil
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -123,7 +123,7 @@ describe HaveAPI::Authentication::Basic::Provider do
|
|
|
123
123
|
expect(last_response.status).to eq(401)
|
|
124
124
|
expect(last_response.headers['www-authenticate']).to include('Basic realm=')
|
|
125
125
|
expect(api_response).to be_failed
|
|
126
|
-
expect(api_response.message).to
|
|
126
|
+
expect(api_response.message).to eq('This action requires authentication')
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
it 'returns an authentication error envelope from _logout' do
|
|
@@ -132,6 +132,6 @@ describe HaveAPI::Authentication::Basic::Provider do
|
|
|
132
132
|
expect(last_response.status).to eq(401)
|
|
133
133
|
expect(last_response.headers['www-authenticate']).to include('Basic realm=')
|
|
134
134
|
expect(api_response).to be_failed
|
|
135
|
-
expect(api_response.message).to
|
|
135
|
+
expect(api_response.message).to eq('This action requires authentication')
|
|
136
136
|
end
|
|
137
137
|
end
|
|
@@ -225,7 +225,7 @@ describe HaveAPI::Authentication::OAuth2 do
|
|
|
225
225
|
|
|
226
226
|
expect(last_response.status).to eq(400)
|
|
227
227
|
expect(api_response).to be_failed
|
|
228
|
-
expect(api_response.message).to eq('Bylo
|
|
228
|
+
expect(api_response.message).to eq('Bylo zadáno více OAuth2 tokenů')
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
it 'ignores structured access_token query values before backend lookup' do
|
|
@@ -248,6 +248,7 @@ describe HaveAPI::Authentication::OAuth2 do
|
|
|
248
248
|
end
|
|
249
249
|
|
|
250
250
|
it 'exposes oauth2 provider in version description' do
|
|
251
|
+
header 'Accept-Language', 'cs'
|
|
251
252
|
call_api(:options, '/v1/')
|
|
252
253
|
|
|
253
254
|
expect(last_response.status).to eq(200)
|
|
@@ -257,6 +258,7 @@ describe HaveAPI::Authentication::OAuth2 do
|
|
|
257
258
|
expect(auth).to have_key(:oauth2)
|
|
258
259
|
|
|
259
260
|
desc = auth[:oauth2]
|
|
261
|
+
expect(desc[:description]).to start_with('OAuth2 autorizační provider')
|
|
260
262
|
expect(desc).to have_key(:http_header)
|
|
261
263
|
expect(desc[:http_header]).to eq('X-HaveAPI-OAuth2-Token')
|
|
262
264
|
|
|
@@ -290,6 +290,7 @@ describe HaveAPI::Authentication::Token do
|
|
|
290
290
|
end
|
|
291
291
|
|
|
292
292
|
it 'exposes token provider in version description' do
|
|
293
|
+
header 'Accept-Language', 'cs'
|
|
293
294
|
call_api(:options, '/v1/')
|
|
294
295
|
|
|
295
296
|
expect(last_response.status).to eq(200)
|
|
@@ -297,11 +298,18 @@ describe HaveAPI::Authentication::Token do
|
|
|
297
298
|
|
|
298
299
|
auth = api_response[:authentication]
|
|
299
300
|
expect(auth).to have_key(:token)
|
|
301
|
+
expect(auth[:token][:description]).to start_with('Klient se autentizuje')
|
|
300
302
|
expect(auth[:token][:http_header]).to eq(AuthSpecToken::Config.http_header)
|
|
301
303
|
expect(auth[:token][:query_parameter]).to eq(AuthSpecToken::Config.query_parameter.to_s)
|
|
302
304
|
|
|
303
305
|
expect(auth[:token]).to have_key(:resources)
|
|
304
306
|
expect(auth[:token][:resources]).to have_key(:token)
|
|
307
|
+
|
|
308
|
+
resource = auth[:token][:resources][:token]
|
|
309
|
+
expect(resource[:description]).to eq('Spravovat autentizační tokeny')
|
|
310
|
+
expect(resource[:actions][:request][:description]).to eq('Vyžádat autentizační token')
|
|
311
|
+
expect(resource[:actions][:revoke][:description]).to eq('Zneplatnit aktuální autentizační token')
|
|
312
|
+
expect(resource[:actions][:renew][:description]).to eq('Obnovit aktuální autentizační token')
|
|
305
313
|
end
|
|
306
314
|
end
|
|
307
315
|
|
|
@@ -113,7 +113,7 @@ describe HaveAPI::Extensions::ExceptionMailer do
|
|
|
113
113
|
|
|
114
114
|
expect(last_response.status).to eq(500)
|
|
115
115
|
expect(api_response).not_to be_ok
|
|
116
|
-
expect(api_response.message).to eq('
|
|
116
|
+
expect(api_response.message).to eq('A server error occurred')
|
|
117
117
|
|
|
118
118
|
expect(calls.size).to eq(1)
|
|
119
119
|
context, exception, body = calls.first
|
|
@@ -190,6 +190,6 @@ describe HaveAPI::Extensions::ExceptionMailer do
|
|
|
190
190
|
|
|
191
191
|
expect(last_response.status).to eq(500)
|
|
192
192
|
expect(api_response).not_to be_ok
|
|
193
|
-
expect(api_response.message).to eq('
|
|
193
|
+
expect(api_response.message).to eq('A server error occurred')
|
|
194
194
|
end
|
|
195
195
|
end
|