haveapi 0.29.2 → 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/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/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 +52 -9
- data/spec/model_adapters/active_record_spec.rb +8 -8
- data/spec/server/integration_spec.rb +5 -5
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 885ac3cc2e4b40ee6595f9beadad79e75f371d607dd0d49d02f67a01cece7d7f
|
|
4
|
+
data.tar.gz: 8c8b186ae1299655f952bedf5cd857042df97b060a0fda7e43ef6b9bc0ec6393
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b3cd3b9dabb84f88119dde487b150ea6694ab76450d24df1c8f7ff9309b5fcb91638d58f4794db0236de5d8a81c01693c3a5adfc9665200bdb24915599d131e
|
|
7
|
+
data.tar.gz: c738c43d4cc3437124e9af50cd1ae70c84d3f5a91cb93f4c6d1b0966257e011f438f8ecf36639ba0da5044b0b06aa5c8b6072dce4793d4546df424ebdc50a1a9
|
data/haveapi.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
s.required_ruby_version = ">= #{File.read('../../.ruby-version').strip}"
|
|
16
16
|
|
|
17
17
|
s.add_dependency 'activesupport', '>= 7.1'
|
|
18
|
-
s.add_dependency 'haveapi-client', '~> 0.29.
|
|
18
|
+
s.add_dependency 'haveapi-client', '~> 0.29.3'
|
|
19
19
|
s.add_dependency 'i18n', '>= 1.6', '< 2'
|
|
20
20
|
s.add_dependency 'json'
|
|
21
21
|
s.add_dependency 'mail'
|
|
@@ -38,8 +38,7 @@ module HaveAPI::Authentication
|
|
|
38
38
|
|
|
39
39
|
def describe
|
|
40
40
|
{
|
|
41
|
-
description: '
|
|
42
|
-
'via HTTP header. Its use is forbidden from web browsers.'
|
|
41
|
+
description: HaveAPI.message('haveapi.authentication.basic.description')
|
|
43
42
|
}
|
|
44
43
|
end
|
|
45
44
|
|
|
@@ -54,7 +54,7 @@ module HaveAPI::Authentication
|
|
|
54
54
|
return ret unless @instances[context.version]
|
|
55
55
|
|
|
56
56
|
@instances[context.version].each do |provider|
|
|
57
|
-
ret[provider.name] = provider.describe
|
|
57
|
+
ret[provider.name] = HaveAPI.localize(provider.describe)
|
|
58
58
|
|
|
59
59
|
next unless provider.resource_module
|
|
60
60
|
|
|
@@ -150,24 +150,8 @@ module HaveAPI::Authentication
|
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
def describe
|
|
153
|
-
desc = <<-END
|
|
154
|
-
OAuth2 authorization provider. While OAuth2 support in HaveAPI clients
|
|
155
|
-
is limited, it is possible to use your API as an authentication source
|
|
156
|
-
and to use OAuth2 tokens to access the API.
|
|
157
|
-
|
|
158
|
-
HaveAPI partially implements RFC 6749: authorization response type "code"
|
|
159
|
-
and token grant types "authorization_code" and "refresh_token". Other
|
|
160
|
-
response and grant types are not supported at this time.
|
|
161
|
-
|
|
162
|
-
The access token can be passed as bearer token according to RFC 6750,
|
|
163
|
-
or using a custom HTTP header when the Authorization header is not
|
|
164
|
-
practical.
|
|
165
|
-
|
|
166
|
-
The access and refresh tokens can be revoked as per RFC 7009.
|
|
167
|
-
END
|
|
168
|
-
|
|
169
153
|
{
|
|
170
|
-
description:
|
|
154
|
+
description: HaveAPI.message('haveapi.authentication.oauth2.description'),
|
|
171
155
|
http_header: config.http_header,
|
|
172
156
|
authorize_url: @authorize_url,
|
|
173
157
|
authorize_path: @authorize_path,
|
|
@@ -185,7 +185,7 @@ module HaveAPI::Authentication
|
|
|
185
185
|
{
|
|
186
186
|
http_header: config.class.http_header,
|
|
187
187
|
query_parameter: config.class.query_parameter,
|
|
188
|
-
description: '
|
|
188
|
+
description: HaveAPI.message('haveapi.authentication.token.description')
|
|
189
189
|
}
|
|
190
190
|
end
|
|
191
191
|
|
|
@@ -203,12 +203,16 @@ module HaveAPI::Authentication
|
|
|
203
203
|
provider = self
|
|
204
204
|
|
|
205
205
|
HaveAPI::Resource.define_resource(:Token) do
|
|
206
|
+
desc HaveAPI.message('haveapi.authentication.token.resource.description')
|
|
207
|
+
|
|
206
208
|
define_singleton_method(:token_instance) { provider }
|
|
207
209
|
|
|
208
210
|
auth false
|
|
209
211
|
version :all
|
|
210
212
|
|
|
211
213
|
define_action(:Request) do
|
|
214
|
+
desc HaveAPI.message('haveapi.authentication.token.actions.request.description')
|
|
215
|
+
|
|
212
216
|
route ''
|
|
213
217
|
http_method :post
|
|
214
218
|
|
|
@@ -275,6 +279,8 @@ module HaveAPI::Authentication
|
|
|
275
279
|
end
|
|
276
280
|
|
|
277
281
|
define_action(:Revoke) do
|
|
282
|
+
desc HaveAPI.message('haveapi.authentication.token.actions.revoke.description')
|
|
283
|
+
|
|
278
284
|
http_method :post
|
|
279
285
|
auth true
|
|
280
286
|
|
|
@@ -318,6 +324,8 @@ module HaveAPI::Authentication
|
|
|
318
324
|
end
|
|
319
325
|
|
|
320
326
|
define_action(:Renew) do
|
|
327
|
+
desc HaveAPI.message('haveapi.authentication.token.actions.renew.description')
|
|
328
|
+
|
|
321
329
|
http_method :post
|
|
322
330
|
auth true
|
|
323
331
|
|
data/lib/haveapi/locales/cs.yml
CHANGED
|
@@ -5,33 +5,57 @@
|
|
|
5
5
|
cs:
|
|
6
6
|
haveapi:
|
|
7
7
|
action_state:
|
|
8
|
-
cancellation_failed:
|
|
9
|
-
not_found:
|
|
10
|
-
timeout_max:
|
|
8
|
+
cancellation_failed: Zrušení akce se nezdařilo
|
|
9
|
+
not_found: Stav akce nebyl nalezen
|
|
10
|
+
timeout_max: Časový limit může být nejvýše %{max}
|
|
11
11
|
authentication:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
basic:
|
|
13
|
+
description: |-
|
|
14
|
+
Autentizace pomocí HTTP Basic. Uživatelské jméno a heslo se předávají v HTTP hlavičce.
|
|
15
|
+
Tato metoda se nesmí používat z webových prohlížečů.
|
|
16
|
+
failed: Přihlášení se nezdařilo
|
|
17
|
+
invalid_credentials: Neplatné přihlašovací údaje
|
|
18
|
+
multiple_oauth2_tokens: Bylo zadáno více OAuth2 tokenů
|
|
19
|
+
multiple_tokens: Bylo zadáno více autentizačních tokenů
|
|
20
|
+
oauth2:
|
|
21
|
+
description: |-
|
|
22
|
+
OAuth2 autorizační provider.
|
|
23
|
+
Podpora OAuth2 v klientech HaveAPI je omezená, ale API lze použít jako zdroj autentizace a k přístupu k API lze používat OAuth2 tokeny. HaveAPI částečně implementuje RFC 6749: autorizační response type "code" a token grant types "authorization_code" a "refresh_token". Ostatní response a grant types momentálně nejsou podporovány. Přístupový token lze předat jako bearer token podle RFC 6750 nebo vlastní HTTP hlavičkou, pokud není praktické použít hlavičku Authorization.
|
|
24
|
+
Přístupové a refresh tokeny lze zneplatnit podle RFC 7009.
|
|
25
|
+
renew_failed: Obnovení tokenu se nezdařilo
|
|
26
|
+
required: Tato akce vyžaduje přihlášení
|
|
27
|
+
revoke_failed: Zneplatnění tokenu se nezdařilo
|
|
28
|
+
token:
|
|
29
|
+
actions:
|
|
30
|
+
renew:
|
|
31
|
+
description: Obnovit aktuální autentizační token
|
|
32
|
+
request:
|
|
33
|
+
description: Vyžádat autentizační token
|
|
34
|
+
revoke:
|
|
35
|
+
description: Zneplatnit aktuální autentizační token
|
|
36
|
+
description: Klient se autentizuje přihlašovacími údaji, obvykle uživatelským
|
|
37
|
+
jménem a heslem, a získá token. Od té chvíle už přihlašovací údaje nepotřebuje
|
|
38
|
+
a používá místo nich token. Tokeny mohou mít různou dobu platnosti a lze
|
|
39
|
+
je obnovovat nebo zneplatňovat. Token se předává buď v HTTP hlavičce, nebo
|
|
40
|
+
jako parametr dotazu.
|
|
41
|
+
resource:
|
|
42
|
+
description: Spravovat autentizační tokeny
|
|
43
|
+
token_required: Tato akce vyžaduje autentizaci tokenem
|
|
20
44
|
authorization:
|
|
21
45
|
insufficient_permissions: Přístup odepřen. Nedostatečná oprávnění.
|
|
22
46
|
errors:
|
|
23
47
|
action_not_found: Akce nebyla nalezena
|
|
24
|
-
bad_accept_header:
|
|
25
|
-
bad_json_syntax:
|
|
26
|
-
json_body_object: Tělo JSON musí být objekt
|
|
48
|
+
bad_accept_header: Neplatná hlavička Accept
|
|
49
|
+
bad_json_syntax: Neplatná syntaxe JSON
|
|
50
|
+
json_body_object: Tělo JSON požadavku musí být objekt
|
|
27
51
|
server_error: Došlo k chybě serveru
|
|
28
|
-
unsupported_content_type:
|
|
52
|
+
unsupported_content_type: Nepodporovaná hlavička Content-Type
|
|
29
53
|
pagination:
|
|
30
|
-
limit_max:
|
|
54
|
+
limit_max: Limit může být nejvýše %{max}
|
|
31
55
|
parameters:
|
|
32
56
|
action_state:
|
|
33
57
|
can_cancel:
|
|
34
|
-
description: Je-li true,
|
|
58
|
+
description: Je-li hodnota true, lze běh této akce zrušit
|
|
35
59
|
label: Lze zrušit
|
|
36
60
|
created_at:
|
|
37
61
|
label: Vytvořeno
|
|
@@ -43,98 +67,111 @@ cs:
|
|
|
43
67
|
label: Popisek
|
|
44
68
|
poll:
|
|
45
69
|
current:
|
|
46
|
-
description: průběh
|
|
70
|
+
description: Aktuální průběh pro porovnání, je-li nastaveno update_in
|
|
47
71
|
status:
|
|
48
|
-
description:
|
|
72
|
+
description: Stav pro porovnání, je-li nastaveno update_in
|
|
49
73
|
timeout:
|
|
50
|
-
description: v sekundách
|
|
74
|
+
description: Časový limit v sekundách
|
|
51
75
|
label: Časový limit
|
|
52
76
|
total:
|
|
53
|
-
description: průběh
|
|
77
|
+
description: Celkový průběh pro porovnání, je-li nastaveno update_in
|
|
54
78
|
update_in:
|
|
55
|
-
description:
|
|
56
|
-
|
|
79
|
+
description: Vrátit stav dříve, pokud se změní status, current nebo total;
|
|
80
|
+
hodnota se předává implementacím pollingu v API
|
|
81
|
+
label: Čekat na změnu
|
|
57
82
|
status:
|
|
58
|
-
description: Určuje, zda akce probíhá nebo
|
|
83
|
+
description: Určuje, zda akce probíhá úspěšně nebo selhala
|
|
59
84
|
label: Stav
|
|
60
85
|
total:
|
|
61
|
-
description: Akce je dokončena, když
|
|
86
|
+
description: Akce je dokončena, když aktuální průběh dosáhne celkového
|
|
62
87
|
label: Celkem
|
|
63
88
|
unit:
|
|
64
|
-
description: Jednotka
|
|
89
|
+
description: Jednotka hodnot current a total
|
|
65
90
|
label: Jednotka
|
|
66
91
|
updated_at:
|
|
67
|
-
description:
|
|
92
|
+
description: Čas poslední aktualizace průběhu
|
|
68
93
|
label: Aktualizováno
|
|
69
94
|
action_state_id:
|
|
70
|
-
description:
|
|
71
|
-
|
|
95
|
+
description: |-
|
|
96
|
+
ID objektu ActionState pro dotazování na stav.
|
|
97
|
+
Pokud je hodnota null, akce v aktuálním volání neblokuje.
|
|
72
98
|
label: ID stavu akce
|
|
73
99
|
active_record:
|
|
74
100
|
includes:
|
|
75
|
-
description:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Pro přeložení dalších asociací uzlu použijte např. 'user,node__location',
|
|
80
|
-
pro ještě hlubší úroveň např. 'user,node__location__environment'.
|
|
101
|
+
description: Seznam názvů asociovaných zdrojů oddělených čárkou. Vnořené
|
|
102
|
+
asociace se zapisují pomocí '__' mezi názvy zdrojů. Například 'user,node'
|
|
103
|
+
načte tyto dvě asociace. Pro načtení dalších asociací zdroje node použijte
|
|
104
|
+
např. 'user,node__location'; pro ještě hlubší úroveň např. 'user,node__location__environment'.
|
|
81
105
|
label: Zahrnuté asociace
|
|
82
106
|
path_params:
|
|
83
|
-
description: Pole parametrů potřebných k
|
|
107
|
+
description: Pole parametrů potřebných k sestavení URL k tomuto objektu
|
|
84
108
|
label: Parametry URL
|
|
85
109
|
resolved:
|
|
86
|
-
description: True, pokud je asociace
|
|
87
|
-
label:
|
|
110
|
+
description: True, pokud je asociace načtena
|
|
111
|
+
label: Načteno
|
|
88
112
|
authentication:
|
|
89
113
|
token:
|
|
90
114
|
interval:
|
|
91
|
-
description:
|
|
115
|
+
description: Doba platnosti požadovaného tokenu v sekundách.
|
|
92
116
|
label: Interval
|
|
93
117
|
lifetime:
|
|
94
118
|
description: |-
|
|
95
119
|
fixed - token má pevnou dobu platnosti a nelze ho obnovit
|
|
96
|
-
renewable_manual -
|
|
97
|
-
renewable_auto -
|
|
98
|
-
permanent - token
|
|
120
|
+
renewable_manual - platnost tokenu lze prodloužit, ale pouze ručně akcí renew
|
|
121
|
+
renewable_auto - platnost tokenu se při každém použití automaticky prodlouží na now + interval
|
|
122
|
+
permanent - token je platný trvale, dokud není smazán
|
|
99
123
|
label: Životnost
|
|
100
124
|
password:
|
|
101
125
|
label: Heslo
|
|
102
126
|
scope:
|
|
103
|
-
label:
|
|
127
|
+
label: Scope
|
|
104
128
|
user:
|
|
105
129
|
label: Uživatel
|
|
106
130
|
default:
|
|
107
131
|
count:
|
|
108
|
-
label: Vrátit počet
|
|
132
|
+
label: Vrátit celkový počet položek
|
|
109
133
|
total_count:
|
|
110
|
-
label: Celkový počet
|
|
134
|
+
label: Celkový počet položek
|
|
111
135
|
metadata:
|
|
112
136
|
'no':
|
|
113
|
-
label:
|
|
137
|
+
label: Vypnout metadata
|
|
114
138
|
paginable:
|
|
115
139
|
from_id:
|
|
116
|
-
description: Vypsat objekty s větším/menším
|
|
140
|
+
description: Vypsat objekty s ID větším/menším než zadaná hodnota
|
|
117
141
|
label: Od ID
|
|
118
142
|
limit:
|
|
119
143
|
description: Počet objektů k načtení
|
|
120
144
|
label: Limit
|
|
145
|
+
resources:
|
|
146
|
+
action_state:
|
|
147
|
+
actions:
|
|
148
|
+
cancel:
|
|
149
|
+
description: Zrušit čekající akci
|
|
150
|
+
index:
|
|
151
|
+
description: Vypsat stavy čekajících akcí
|
|
152
|
+
poll:
|
|
153
|
+
description: Vrátit stav po dokončení akce, změně průběhu nebo vypršení
|
|
154
|
+
časového limitu
|
|
155
|
+
show:
|
|
156
|
+
description: Zobrazit stav čekající akce
|
|
157
|
+
description: Procházet stavy blokujících akcí
|
|
121
158
|
types:
|
|
122
|
-
invalid_boolean:
|
|
123
|
-
invalid_datetime: není ve formátu ISO 8601 '%{value}'
|
|
124
|
-
invalid_float:
|
|
125
|
-
invalid_integer:
|
|
126
|
-
invalid_string:
|
|
159
|
+
invalid_boolean: 'není platná pravdivostní hodnota: %{value}'
|
|
160
|
+
invalid_datetime: 'není ve formátu ISO 8601: ''%{value}'''
|
|
161
|
+
invalid_float: 'není platné desetinné číslo: %{value}'
|
|
162
|
+
invalid_integer: 'není platné celé číslo: %{value}'
|
|
163
|
+
invalid_string: 'není platný řetězec: %{value}'
|
|
127
164
|
validation:
|
|
128
165
|
cannot_be_null: nesmí být null
|
|
129
166
|
includes_only_strings: includes musí obsahovat jen řetězce
|
|
130
167
|
includes_string_or_array: includes musí být řetězec nebo pole
|
|
131
|
-
input_parameters_not_valid: vstupní parametry
|
|
132
|
-
invalid_id:
|
|
168
|
+
input_parameters_not_valid: vstupní parametry jsou neplatné
|
|
169
|
+
invalid_id: 'není platné ID: %{value}'
|
|
133
170
|
invalid_input_layout: neplatná struktura vstupu
|
|
134
171
|
invalid_path_parameter_encoding: neplatné kódování parametru cesty
|
|
135
172
|
invalid_string_encoding: neplatné kódování řetězce
|
|
136
|
-
required_parameter_missing: povinný parametr
|
|
137
|
-
resource_not_found:
|
|
173
|
+
required_parameter_missing: chybí povinný parametr
|
|
174
|
+
resource_not_found: zdroj nebyl nalezen
|
|
138
175
|
validators:
|
|
139
176
|
acceptance:
|
|
140
177
|
accepted: musí být %{value}
|
|
@@ -149,19 +186,19 @@ cs:
|
|
|
149
186
|
included: "%{value} nelze použít"
|
|
150
187
|
length:
|
|
151
188
|
equals: délka musí být %{equals}
|
|
152
|
-
max: délka
|
|
189
|
+
max: délka musí být nejvýše %{max}
|
|
153
190
|
min: délka musí být alespoň %{min}
|
|
154
|
-
range: délka musí být v rozsahu
|
|
191
|
+
range: délka musí být v rozsahu %{min}–%{max}
|
|
155
192
|
numericality:
|
|
156
193
|
composite: "%{requirements}"
|
|
157
|
-
even: sudé číslo
|
|
194
|
+
even: musí být sudé číslo
|
|
158
195
|
max: musí být nejvýše %{max}
|
|
159
196
|
min: musí být alespoň %{min}
|
|
160
197
|
mod: zbytek po dělení %{mod} musí být nula
|
|
161
198
|
number: musí být číslo
|
|
162
|
-
odd: liché číslo
|
|
163
|
-
range: musí být v rozsahu
|
|
164
|
-
step: v krocích po %{step}
|
|
199
|
+
odd: musí být liché číslo
|
|
200
|
+
range: musí být v rozsahu %{min}–%{max}
|
|
201
|
+
step: musí být v krocích po %{step}
|
|
165
202
|
presence:
|
|
166
|
-
non_empty: musí být vyplněno a
|
|
203
|
+
non_empty: musí být vyplněno a nesmí být prázdné
|
|
167
204
|
present: musí být vyplněno
|
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
|
|
@@ -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
|
data/spec/i18n_spec.rb
CHANGED
|
@@ -10,6 +10,16 @@ module I18nSpec
|
|
|
10
10
|
User.new(:cs) if username == 'user' && password == 'pass'
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
module ActionStateBackend
|
|
15
|
+
def self.list_pending(*)
|
|
16
|
+
[]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.new(*)
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
13
23
|
end
|
|
14
24
|
|
|
15
25
|
describe HaveAPI::I18n do
|
|
@@ -113,8 +123,8 @@ describe HaveAPI::I18n do
|
|
|
113
123
|
header 'Accept', 'application/json'
|
|
114
124
|
call_api(:post, '/v1/things', thing: {})
|
|
115
125
|
|
|
116
|
-
expect(api_response.message).to eq('input parameters not valid')
|
|
117
|
-
expect(api_response.errors[:name]).to include('required parameter missing')
|
|
126
|
+
expect(api_response.message).to eq('input parameters are not valid')
|
|
127
|
+
expect(api_response.errors[:name]).to include('required parameter is missing')
|
|
118
128
|
expect(last_response.headers['Vary']).to include('Accept-Language')
|
|
119
129
|
end
|
|
120
130
|
|
|
@@ -123,9 +133,9 @@ describe HaveAPI::I18n do
|
|
|
123
133
|
header 'Accept-Language', 'cs'
|
|
124
134
|
call_api(:post, '/v1/things', thing: { count: 'nope' })
|
|
125
135
|
|
|
126
|
-
expect(api_response.message).to eq('vstupní parametry
|
|
127
|
-
expect(api_response.errors[:name]).to include('povinný parametr
|
|
128
|
-
expect(api_response.errors[:count].first).to include('
|
|
136
|
+
expect(api_response.message).to eq('vstupní parametry jsou neplatné')
|
|
137
|
+
expect(api_response.errors[:name]).to include('chybí povinný parametr')
|
|
138
|
+
expect(api_response.errors[:count].first).to include('není platné celé číslo')
|
|
129
139
|
expect(last_response.headers['Vary']).to include('Accept-Language')
|
|
130
140
|
end
|
|
131
141
|
|
|
@@ -151,7 +161,7 @@ describe HaveAPI::I18n do
|
|
|
151
161
|
options '/v1/things', method: 'POST'
|
|
152
162
|
|
|
153
163
|
length = api_response[:input][:parameters][:name][:validators][:length]
|
|
154
|
-
expect(length[:message]).to eq('délka musí být v rozsahu
|
|
164
|
+
expect(length[:message]).to eq('délka musí být v rozsahu 3–5')
|
|
155
165
|
end
|
|
156
166
|
|
|
157
167
|
it 'keeps untranslated array choices unchanged in OPTIONS responses' do
|
|
@@ -393,7 +403,7 @@ describe HaveAPI::I18n do
|
|
|
393
403
|
create = api_response[:resources][:thing][:actions][:create]
|
|
394
404
|
no_meta = create[:meta][:global][:input][:parameters][:no]
|
|
395
405
|
|
|
396
|
-
expect(no_meta[:label]).to eq('
|
|
406
|
+
expect(no_meta[:label]).to eq('Vypnout metadata')
|
|
397
407
|
end
|
|
398
408
|
|
|
399
409
|
it 'localizes application-supplied lazy validator messages' do
|
|
@@ -459,7 +469,7 @@ describe HaveAPI::I18n do
|
|
|
459
469
|
expect(HaveAPI.localize(data)).to eq({
|
|
460
470
|
message: 'Akce nebyla nalezena',
|
|
461
471
|
errors: {
|
|
462
|
-
name: ['povinný parametr
|
|
472
|
+
name: ['chybí povinný parametr']
|
|
463
473
|
}
|
|
464
474
|
})
|
|
465
475
|
ensure
|
|
@@ -492,6 +502,39 @@ describe HaveAPI::I18n do
|
|
|
492
502
|
end
|
|
493
503
|
end
|
|
494
504
|
|
|
505
|
+
context 'with localized framework self-description' do
|
|
506
|
+
empty_api
|
|
507
|
+
use_version 1
|
|
508
|
+
default_version 1
|
|
509
|
+
auth_chain I18nSpec::Provider
|
|
510
|
+
action_state I18nSpec::ActionStateBackend
|
|
511
|
+
|
|
512
|
+
before do
|
|
513
|
+
header 'Accept', 'application/json'
|
|
514
|
+
header 'Accept-Language', 'cs'
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
it 'localizes authentication provider descriptions' do
|
|
518
|
+
call_api(:options, '/?describe=default')
|
|
519
|
+
|
|
520
|
+
description = api_response[:authentication][:basic][:description]
|
|
521
|
+
expect(description).to start_with('Autentizace pomocí HTTP Basic')
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it 'localizes ActionState resource and action descriptions' do
|
|
525
|
+
call_api(:options, '/?describe=default')
|
|
526
|
+
|
|
527
|
+
action_state = api_response[:resources][:action_state]
|
|
528
|
+
expect(action_state[:description]).to eq('Procházet stavy blokujících akcí')
|
|
529
|
+
expect(action_state[:actions][:index][:description]).to eq('Vypsat stavy čekajících akcí')
|
|
530
|
+
expect(action_state[:actions][:poll][:description]).to eq(
|
|
531
|
+
'Vrátit stav po dokončení akce, změně průběhu nebo vypršení časového limitu'
|
|
532
|
+
)
|
|
533
|
+
expect(action_state[:actions][:show][:description]).to eq('Zobrazit stav čekající akce')
|
|
534
|
+
expect(action_state[:actions][:cancel][:description]).to eq('Zrušit čekající akci')
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
495
538
|
context 'with an authenticated locale resolver' do
|
|
496
539
|
api do
|
|
497
540
|
define_resource(:Thing) do
|
|
@@ -525,7 +568,7 @@ describe HaveAPI::I18n do
|
|
|
525
568
|
|
|
526
569
|
action = api_response[:resources][:thing][:actions][:create]
|
|
527
570
|
length = action.dig(:input, :parameters, :name, :validators, :length)
|
|
528
|
-
expect(length[:message]).to eq('délka musí být v rozsahu
|
|
571
|
+
expect(length[:message]).to eq('délka musí být v rozsahu 3–5')
|
|
529
572
|
end
|
|
530
573
|
end
|
|
531
574
|
|
|
@@ -869,23 +869,23 @@ describe HaveAPI::ModelAdapters::ActiveRecord do
|
|
|
869
869
|
|
|
870
870
|
expect do
|
|
871
871
|
described_class::Input.clean(ARAdapterSpec::Environment, 'abc', {})
|
|
872
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
872
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
873
873
|
|
|
874
874
|
expect do
|
|
875
875
|
described_class::Input.clean(ARAdapterSpec::Environment, '', {})
|
|
876
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
876
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
877
877
|
|
|
878
878
|
expect do
|
|
879
879
|
described_class::Input.clean(ARAdapterSpec::Environment, 1.2, {})
|
|
880
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
880
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
881
881
|
|
|
882
882
|
expect do
|
|
883
883
|
described_class::Input.clean(ARAdapterSpec::Environment, false, {})
|
|
884
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
884
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
885
885
|
|
|
886
886
|
expect do
|
|
887
887
|
described_class::Input.clean(ARAdapterSpec::Environment, true, {})
|
|
888
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
888
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
889
889
|
|
|
890
890
|
expect do
|
|
891
891
|
described_class::Input.clean(ARAdapterSpec::Environment, 9999, {})
|
|
@@ -913,11 +913,11 @@ describe HaveAPI::ModelAdapters::ActiveRecord do
|
|
|
913
913
|
|
|
914
914
|
expect do
|
|
915
915
|
described_class::Input.clean(ARAdapterSpec::StringAccount, %w[acct-alpha acct-beta], {})
|
|
916
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
916
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
917
917
|
|
|
918
918
|
expect do
|
|
919
919
|
described_class::Input.clean(ARAdapterSpec::StringAccount, { id: 'acct-alpha' }, {})
|
|
920
|
-
end.to raise_error(HaveAPI::ValidationError, /not a valid
|
|
920
|
+
end.to raise_error(HaveAPI::ValidationError, /not a valid ID/)
|
|
921
921
|
end
|
|
922
922
|
|
|
923
923
|
it 'rejects non-string includes metadata entries' do
|
|
@@ -957,7 +957,7 @@ describe HaveAPI::ModelAdapters::ActiveRecord do
|
|
|
957
957
|
expect(last_response.status).to eq(200)
|
|
958
958
|
expect(api_response).not_to be_ok
|
|
959
959
|
expect(api_response.errors[:limit].first).to include(
|
|
960
|
-
"
|
|
960
|
+
"between 0 and #{HaveAPI::Actions::Paginable::MAX_LIMIT}"
|
|
961
961
|
)
|
|
962
962
|
end
|
|
963
963
|
|
|
@@ -97,7 +97,7 @@ describe HaveAPI::Server do
|
|
|
97
97
|
|
|
98
98
|
expect(last_response.status).to eq(400)
|
|
99
99
|
expect(api_response).not_to be_ok
|
|
100
|
-
expect(api_response.message).to match(/
|
|
100
|
+
expect(api_response.message).to match(/Invalid JSON syntax/)
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
it 'returns 400 for non-object JSON bodies' do
|
|
@@ -109,7 +109,7 @@ describe HaveAPI::Server do
|
|
|
109
109
|
|
|
110
110
|
expect(last_response.status).to eq(400)
|
|
111
111
|
expect(api_response).not_to be_ok
|
|
112
|
-
expect(api_response.message).to eq('JSON body must be an object')
|
|
112
|
+
expect(api_response.message).to eq('The JSON request body must be an object')
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
115
|
|
|
@@ -132,7 +132,7 @@ describe HaveAPI::Server do
|
|
|
132
132
|
|
|
133
133
|
expect(last_response.status).to eq(415)
|
|
134
134
|
expect(api_response).not_to be_ok
|
|
135
|
-
expect(api_response.message).to eq('Unsupported Content-Type')
|
|
135
|
+
expect(api_response.message).to eq('Unsupported Content-Type header')
|
|
136
136
|
expect(ServerIntegrationSpec::State.writes).to be_empty
|
|
137
137
|
end
|
|
138
138
|
|
|
@@ -145,7 +145,7 @@ describe HaveAPI::Server do
|
|
|
145
145
|
|
|
146
146
|
expect(last_response.status).to eq(400)
|
|
147
147
|
expect(api_response).not_to be_ok
|
|
148
|
-
expect(api_response.message).to eq('
|
|
148
|
+
expect(api_response.message).to eq('Invalid Accept header')
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
it 'returns JSON envelope for unknown route' do
|
|
@@ -169,7 +169,7 @@ describe HaveAPI::Server do
|
|
|
169
169
|
|
|
170
170
|
expect(last_response.status).to eq(500)
|
|
171
171
|
expect(api_response).not_to be_ok
|
|
172
|
-
expect(api_response.message).to eq('
|
|
172
|
+
expect(api_response.message).to eq('A server error occurred')
|
|
173
173
|
|
|
174
174
|
expect(calls.size).to eq(1)
|
|
175
175
|
context, exception = calls.first
|
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.29.
|
|
4
|
+
version: 0.29.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jakub Skokan
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.29.
|
|
32
|
+
version: 0.29.3
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.29.
|
|
39
|
+
version: 0.29.3
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: i18n
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|