gds-api-adapters 63.0.0 → 63.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/gds_api/publishing_api.rb +496 -4
- data/lib/gds_api/publishing_api/special_route_publisher.rb +2 -2
- data/lib/gds_api/publishing_api_v2.rb +5 -488
- data/lib/gds_api/test_helpers/publishing_api.rb +760 -29
- data/lib/gds_api/test_helpers/publishing_api_v2.rb +3 -689
- data/lib/gds_api/version.rb +1 -1
- metadata +2 -2
@@ -5,12 +5,630 @@ require "json"
|
|
5
5
|
|
6
6
|
module GdsApi
|
7
7
|
module TestHelpers
|
8
|
+
# @api documented
|
8
9
|
module PublishingApi
|
9
10
|
include ContentItemHelpers
|
10
11
|
include IntentHelpers
|
11
12
|
|
13
|
+
PUBLISHING_API_V2_ENDPOINT = Plek.current.find("publishing-api") + "/v2"
|
12
14
|
PUBLISHING_API_ENDPOINT = Plek.current.find("publishing-api")
|
13
15
|
|
16
|
+
# Stub a PUT /v2/content/:content_id request with the given content id and request body.
|
17
|
+
# if no response_hash is given, a default response as follows is created:
|
18
|
+
# {status: 200, body: '{}', headers: {"Content-Type" => "application/json; charset=utf-8"}}
|
19
|
+
#
|
20
|
+
# if a response is given, then it will be merged with the default response.
|
21
|
+
# if the given parameter for the response body is a Hash, it will be converted to JSON.
|
22
|
+
#
|
23
|
+
# The following two examples are equivalent:
|
24
|
+
# @example
|
25
|
+
# stub_publishing_api_put_content(my_content_id, my_request_body, { status: 201, body: {version: 33}.to_json })
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# stub_publishing_api_put_content(my_content_id, my_request_body, { status: 201, body: {version: 33} })
|
29
|
+
#
|
30
|
+
# @param content_id [UUID]
|
31
|
+
# @param body [String]
|
32
|
+
# @param response_hash [Hash]
|
33
|
+
def stub_publishing_api_put_content(content_id, body, response_hash = {})
|
34
|
+
stub_publishing_api_put(content_id, body, "/content", response_hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Stub a PATCH /v2/links/:content_id request
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# stub_publishing_api_patch_links(
|
41
|
+
# my_content_id,
|
42
|
+
# "links" => {
|
43
|
+
# "taxons" => %w(level_one_topic level_two_topic),
|
44
|
+
# },
|
45
|
+
# "previous_version" => 3,
|
46
|
+
# )
|
47
|
+
#
|
48
|
+
# @param content_id [UUID]
|
49
|
+
# @param body [String]
|
50
|
+
def stub_publishing_api_patch_links(content_id, body)
|
51
|
+
stub_publishing_api_patch(content_id, body, "/links")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Stub a PATCH /v2/links/:content_id request to return a 409 response
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# stub_publishing_api_patch_links_conflict(
|
58
|
+
# my_content_id,
|
59
|
+
# "links" => {
|
60
|
+
# "taxons" => %w(level_one_topic level_two_topic),
|
61
|
+
# },
|
62
|
+
# "previous_version" => 3,
|
63
|
+
# )
|
64
|
+
#
|
65
|
+
# @param content_id [UUID]
|
66
|
+
# @param body [String]
|
67
|
+
def stub_publishing_api_patch_links_conflict(content_id, body)
|
68
|
+
previous_version = JSON.parse(body.to_json)["previous_version"]
|
69
|
+
override_response_hash = { status: 409, body: version_conflict(previous_version) }
|
70
|
+
stub_publishing_api_patch(content_id, body, "/links", override_response_hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Stub a POST /v2/content/:content_id/publish request
|
74
|
+
#
|
75
|
+
# @param content_id [UUID]
|
76
|
+
# @param body [String]
|
77
|
+
# @param response_hash [Hash]
|
78
|
+
def stub_publishing_api_publish(content_id, body, response_hash = {})
|
79
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/publish"
|
80
|
+
response = {
|
81
|
+
status: 200,
|
82
|
+
body: "{}",
|
83
|
+
headers: { "Content-Type" => "application/json; charset=utf-8" },
|
84
|
+
}.merge(response_hash)
|
85
|
+
stub_request(:post, url).with(body: body).to_return(response)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Stub a POST /v2/content/:content_id/republish request
|
89
|
+
#
|
90
|
+
# @param content_id [UUID]
|
91
|
+
# @param body [String]
|
92
|
+
# @param response_hash [Hash]
|
93
|
+
def stub_publishing_api_republish(content_id, body = {}, response_hash = {})
|
94
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/republish"
|
95
|
+
response = {
|
96
|
+
status: 200,
|
97
|
+
body: "{}",
|
98
|
+
headers: { "Content-Type" => "application/json; charset=utf-8" },
|
99
|
+
}.merge(response_hash)
|
100
|
+
stub_request(:post, url).with(body: body).to_return(response)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Stub a POST /v2/content/:content_id/unpublish request
|
104
|
+
#
|
105
|
+
# @param content_id [UUID]
|
106
|
+
# @param params [Hash]
|
107
|
+
# @param body [String]
|
108
|
+
def stub_publishing_api_unpublish(content_id, params, response_hash = {})
|
109
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/unpublish"
|
110
|
+
response = {
|
111
|
+
status: 200,
|
112
|
+
body: "{}",
|
113
|
+
headers: { "Content-Type" => "application/json; charset=utf-8" },
|
114
|
+
}.merge(response_hash)
|
115
|
+
stub_request(:post, url).with(params).to_return(response)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Stub a POST /v2/content/:content_id/discard-draft request
|
119
|
+
#
|
120
|
+
# @param content_id [UUID]
|
121
|
+
def stub_publishing_api_discard_draft(content_id)
|
122
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/discard-draft"
|
123
|
+
stub_request(:post, url).to_return(status: 200, headers: { "Content-Type" => "application/json; charset=utf-8" })
|
124
|
+
end
|
125
|
+
|
126
|
+
# Stub requests issued when publishing a new draft.
|
127
|
+
# - PUT /v2/content/:content_id
|
128
|
+
# - POST /v2/content/:content_id/publish
|
129
|
+
# - PATCH /v2/links/:content_id
|
130
|
+
#
|
131
|
+
# @param body [String]
|
132
|
+
# @param content_id [UUID]
|
133
|
+
# @param publish_body [Hash]
|
134
|
+
def stub_publishing_api_put_content_links_and_publish(body, content_id = nil, publish_body = nil)
|
135
|
+
content_id ||= body[:content_id]
|
136
|
+
if publish_body.nil?
|
137
|
+
publish_body = { update_type: body.fetch(:update_type) }
|
138
|
+
publish_body[:locale] = body[:locale] if body[:locale]
|
139
|
+
end
|
140
|
+
stubs = []
|
141
|
+
stubs << stub_publishing_api_put_content(content_id, body.except(:links))
|
142
|
+
stubs << stub_publishing_api_patch_links(content_id, body.slice(:links)) unless body.slice(:links).empty?
|
143
|
+
stubs << stub_publishing_api_publish(content_id, publish_body)
|
144
|
+
stubs
|
145
|
+
end
|
146
|
+
|
147
|
+
# Stub any PUT /v2/content/* request
|
148
|
+
def stub_any_publishing_api_put_content
|
149
|
+
stub_request(:put, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/content/})
|
150
|
+
end
|
151
|
+
|
152
|
+
# Stub any PATCH /v2/links/* request
|
153
|
+
def stub_any_publishing_api_patch_links
|
154
|
+
stub_request(:patch, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/links/})
|
155
|
+
end
|
156
|
+
|
157
|
+
# Stub any POST /v2/content/*/publish request
|
158
|
+
def stub_any_publishing_api_publish
|
159
|
+
stub_request(:post, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/content/.*/publish})
|
160
|
+
end
|
161
|
+
|
162
|
+
# Stub any POST /v2/content/*/publish request
|
163
|
+
def stub_any_publishing_api_republish
|
164
|
+
stub_request(:post, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/content/.*/republish})
|
165
|
+
end
|
166
|
+
|
167
|
+
# Stub any POST /v2/content/*/unpublish request
|
168
|
+
def stub_any_publishing_api_unpublish
|
169
|
+
stub_request(:post, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/content/.*/unpublish})
|
170
|
+
end
|
171
|
+
|
172
|
+
# Stub any POST /v2/content/*/discard-draft request
|
173
|
+
def stub_any_publishing_api_discard_draft
|
174
|
+
stub_request(:post, %r{\A#{PUBLISHING_API_V2_ENDPOINT}/content/.*/discard-draft})
|
175
|
+
end
|
176
|
+
|
177
|
+
# Stub any version 2 request to the publishing API
|
178
|
+
def stub_any_publishing_api_call
|
179
|
+
stub_request(:any, %r{\A#{PUBLISHING_API_V2_ENDPOINT}})
|
180
|
+
end
|
181
|
+
|
182
|
+
# Stub any version 2 request to the publishing API to return a 404 response
|
183
|
+
def stub_any_publishing_api_call_to_return_not_found
|
184
|
+
stub_request(:any, %r{\A#{PUBLISHING_API_V2_ENDPOINT}})
|
185
|
+
.to_return(status: 404, headers: { "Content-Type" => "application/json; charset=utf-8" })
|
186
|
+
end
|
187
|
+
|
188
|
+
# Stub any version 2 request to the publishing API to return a 503 response
|
189
|
+
def stub_publishing_api_isnt_available
|
190
|
+
stub_request(:any, /#{PUBLISHING_API_V2_ENDPOINT}\/.*/).to_return(status: 503)
|
191
|
+
stub_request(:any, /#{PUBLISHING_API_ENDPOINT}\/.*/).to_return(status: 503)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Assert that a draft was saved and published, and links were updated.
|
195
|
+
# - PUT /v2/content/:content_id
|
196
|
+
# - POST /v2/content/:content_id/publish
|
197
|
+
# - PATCH /v2/links/:content_id
|
198
|
+
#
|
199
|
+
# @param body [String]
|
200
|
+
# @param content_id [UUID]
|
201
|
+
# @param publish_body [Hash]
|
202
|
+
def assert_publishing_api_put_content_links_and_publish(body, content_id = nil, publish_body = nil)
|
203
|
+
content_id ||= body[:content_id]
|
204
|
+
if publish_body.nil?
|
205
|
+
publish_body = { update_type: body.fetch(:update_type) }
|
206
|
+
publish_body[:locale] = body[:locale] if body[:locale]
|
207
|
+
end
|
208
|
+
assert_publishing_api_put_content(content_id, body.except(:links))
|
209
|
+
assert_publishing_api_patch_links(content_id, body.slice(:links)) unless body.slice(:links).empty?
|
210
|
+
assert_publishing_api_publish(content_id, publish_body)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Assert that content was saved (PUT /v2/content/:content_id)
|
214
|
+
#
|
215
|
+
# @param content_id [UUID]
|
216
|
+
# @param attributes_or_matcher [Object]
|
217
|
+
# @param times [Integer]
|
218
|
+
def assert_publishing_api_put_content(content_id, attributes_or_matcher = nil, times = 1)
|
219
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/" + content_id
|
220
|
+
assert_publishing_api(:put, url, attributes_or_matcher, times)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Assert that content was published (POST /v2/content/:content_id/publish)
|
224
|
+
#
|
225
|
+
# @param content_id [UUID]
|
226
|
+
# @param attributes_or_matcher [Object]
|
227
|
+
# @param times [Integer]
|
228
|
+
def assert_publishing_api_publish(content_id, attributes_or_matcher = nil, times = 1)
|
229
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/publish"
|
230
|
+
assert_publishing_api(:post, url, attributes_or_matcher, times)
|
231
|
+
end
|
232
|
+
|
233
|
+
# Assert that content was unpublished (POST /v2/content/:content_id/unpublish)
|
234
|
+
#
|
235
|
+
# @param content_id [UUID]
|
236
|
+
# @param attributes_or_matcher [Object]
|
237
|
+
# @param times [Integer]
|
238
|
+
def assert_publishing_api_unpublish(content_id, attributes_or_matcher = nil, times = 1)
|
239
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/unpublish"
|
240
|
+
assert_publishing_api(:post, url, attributes_or_matcher, times)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Assert that links were updated (PATCH /v2/links/:content_id)
|
244
|
+
#
|
245
|
+
# @param content_id [UUID]
|
246
|
+
# @param attributes_or_matcher [Object]
|
247
|
+
# @param times [Integer]
|
248
|
+
def assert_publishing_api_patch_links(content_id, attributes_or_matcher = nil, times = 1)
|
249
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/links/" + content_id
|
250
|
+
assert_publishing_api(:patch, url, attributes_or_matcher, times)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Assert that a draft was discarded (POST /v2/content/:content_id/discard-draft)
|
254
|
+
#
|
255
|
+
# @param content_id [UUID]
|
256
|
+
# @param attributes_or_matcher [Object]
|
257
|
+
# @param times [Integer]
|
258
|
+
def assert_publishing_api_discard_draft(content_id, attributes_or_matcher = nil, times = 1)
|
259
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/#{content_id}/discard-draft"
|
260
|
+
assert_publishing_api(:post, url, attributes_or_matcher, times)
|
261
|
+
end
|
262
|
+
|
263
|
+
# Assert that a request was made to the publishing API
|
264
|
+
#
|
265
|
+
# @param verb [String]
|
266
|
+
# @param url [String]
|
267
|
+
# @param attributes_or_matcher [Object]
|
268
|
+
# @param times [Integer]
|
269
|
+
def assert_publishing_api(verb, url, attributes_or_matcher = nil, times = 1)
|
270
|
+
if attributes_or_matcher.is_a?(Hash)
|
271
|
+
matcher = request_json_matches(attributes_or_matcher)
|
272
|
+
else
|
273
|
+
matcher = attributes_or_matcher
|
274
|
+
end
|
275
|
+
|
276
|
+
if matcher
|
277
|
+
assert_requested(verb, url, times: times, &matcher)
|
278
|
+
else
|
279
|
+
assert_requested(verb, url, times: times)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Get a request matcher that checks if a JSON request includes a set of attributes
|
284
|
+
def request_json_includes(required_attributes)
|
285
|
+
->(request) do
|
286
|
+
data = JSON.parse(request.body)
|
287
|
+
deep_stringify_keys(required_attributes).
|
288
|
+
to_a.all? { |key, value| data[key] == value }
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Get a request matcher that checks if a JSON request matches a hash
|
293
|
+
def request_json_matches(required_attributes)
|
294
|
+
->(request) do
|
295
|
+
data = JSON.parse(request.body)
|
296
|
+
deep_stringify_keys(required_attributes) == data
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Stub GET /v2/content/ to return a set of content items
|
301
|
+
#
|
302
|
+
# @example
|
303
|
+
#
|
304
|
+
# stub_publishing_api_has_content(
|
305
|
+
# vehicle_recalls_and_faults, # this is a variable containing an array of content items
|
306
|
+
# document_type: described_class.publishing_api_document_type, #example of a document_type: "vehicle_recalls_and_faults_alert"
|
307
|
+
# fields: fields, #example: let(:fields) { %i[base_path content_id public_updated_at title publication_state] }
|
308
|
+
# page: 1,
|
309
|
+
# per_page: 50
|
310
|
+
# )
|
311
|
+
# @param items [Array]
|
312
|
+
# @param params [Hash]
|
313
|
+
def stub_publishing_api_has_content(items, params = {})
|
314
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content"
|
315
|
+
|
316
|
+
if params.respond_to? :fetch
|
317
|
+
per_page = params.fetch(:per_page, 50)
|
318
|
+
page = params.fetch(:page, 1)
|
319
|
+
else
|
320
|
+
per_page = 50
|
321
|
+
page = 1
|
322
|
+
end
|
323
|
+
|
324
|
+
start_position = (page - 1) * per_page
|
325
|
+
page_items = items.slice(start_position, per_page) || []
|
326
|
+
|
327
|
+
number_of_pages =
|
328
|
+
if items.count < per_page
|
329
|
+
1
|
330
|
+
else
|
331
|
+
(items.count / per_page.to_f).ceil
|
332
|
+
end
|
333
|
+
|
334
|
+
body = {
|
335
|
+
results: page_items,
|
336
|
+
total: items.count,
|
337
|
+
pages: number_of_pages,
|
338
|
+
current_page: page,
|
339
|
+
}
|
340
|
+
|
341
|
+
stub_request(:get, url)
|
342
|
+
.with(query: params)
|
343
|
+
.to_return(status: 200, body: body.to_json, headers: {})
|
344
|
+
end
|
345
|
+
|
346
|
+
# This method has been refactored into publishing_api_has_content (above)
|
347
|
+
# publishing_api_has_content allows for flexible passing in of arguments, please use instead
|
348
|
+
def stub_publishing_api_has_fields_for_document(document_type, items, fields)
|
349
|
+
body = Array(items).map { |item|
|
350
|
+
deep_stringify_keys(item).slice(*fields)
|
351
|
+
}
|
352
|
+
|
353
|
+
query_params = fields.map { |f|
|
354
|
+
"&fields%5B%5D=#{f}"
|
355
|
+
}
|
356
|
+
|
357
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content?document_type=#{document_type}#{query_params.join('')}"
|
358
|
+
|
359
|
+
stub_request(:get, url).to_return(status: 200, body: { results: body }.to_json, headers: {})
|
360
|
+
end
|
361
|
+
|
362
|
+
# Stub GET /v2/linkables to return a set of content items with a specific document type
|
363
|
+
#
|
364
|
+
# @param linkables [Array]
|
365
|
+
def stub_publishing_api_has_linkables(linkables, document_type:)
|
366
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/linkables?document_type=#{document_type}"
|
367
|
+
stub_request(:get, url).to_return(status: 200, body: linkables.to_json, headers: {})
|
368
|
+
end
|
369
|
+
|
370
|
+
# Stub GET /v2/content/:content_id to return a specific content item hash
|
371
|
+
#
|
372
|
+
# @param item [Hash]
|
373
|
+
def stub_publishing_api_has_item(item, params = {})
|
374
|
+
item = deep_transform_keys(item, &:to_sym)
|
375
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/" + item[:content_id]
|
376
|
+
stub_request(:get, url)
|
377
|
+
.with(query: hash_including(params))
|
378
|
+
.to_return(status: 200, body: item.to_json, headers: {})
|
379
|
+
end
|
380
|
+
|
381
|
+
# Stub GET /v2/content/:content_id to progress through a series of responses.
|
382
|
+
#
|
383
|
+
# @param items [Array]
|
384
|
+
def stub_publishing_api_has_item_in_sequence(content_id, items)
|
385
|
+
items = items.each { |item| deep_transform_keys(item, &:to_sym) }
|
386
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/" + content_id
|
387
|
+
calls = -1
|
388
|
+
|
389
|
+
stub_request(:get, url).to_return do |_request|
|
390
|
+
calls += 1
|
391
|
+
item = items[calls] || items.last
|
392
|
+
|
393
|
+
{ status: 200, body: item.to_json, headers: {} }
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Stub GET /v2/content/:content_id to return a 404 response
|
398
|
+
#
|
399
|
+
# @param content_id [UUID]
|
400
|
+
def stub_publishing_api_does_not_have_item(content_id)
|
401
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/content/" + content_id
|
402
|
+
stub_request(:get, url).to_return(status: 404, body: resource_not_found(content_id, "content item").to_json, headers: {})
|
403
|
+
end
|
404
|
+
|
405
|
+
# Stub a request to links endpoint
|
406
|
+
#
|
407
|
+
# @param [Hash] links the structure of the links hash
|
408
|
+
#
|
409
|
+
# @example
|
410
|
+
#
|
411
|
+
# stub_publishing_api_has_links(
|
412
|
+
# {
|
413
|
+
# "content_id" => "64aadc14-9bca-40d9-abb6-4f21f9792a05",
|
414
|
+
# "links" => {
|
415
|
+
# "mainstream_browse_pages" => ["df2e7a3e-2078-45de-a75a-fd37d027427e"],
|
416
|
+
# "parent" => ["df2e7a3e-2078-45de-a75a-fd37d027427e"],
|
417
|
+
# "organisations" => ["569a9ee5-c195-4b7f-b9dc-edc17a09113f", "5c54ae52-341b-499e-a6dd-67f04633b8cf"]
|
418
|
+
# },
|
419
|
+
# "version" => 6
|
420
|
+
# }
|
421
|
+
# )
|
422
|
+
#
|
423
|
+
# @example
|
424
|
+
#
|
425
|
+
# Services.publishing_api.get_links("64aadc14-9bca-40d9-abb6-4f21f9792a05")
|
426
|
+
# => {
|
427
|
+
# "content_id" => "64aadc14-9bca-40d9-abb6-4f21f9792a05",
|
428
|
+
# "links" => {
|
429
|
+
# "mainstream_browse_pages" => ["df2e7a3e-2078-45de-a75a-fd37d027427e"],
|
430
|
+
# "parent" => ["df2e7a3e-2078-45de-a75a-fd37d027427e"],
|
431
|
+
# "organisations" => ["569a9ee5-c195-4b7f-b9dc-edc17a09113f", "5c54ae52-341b-499e-a6dd-67f04633b8cf"]
|
432
|
+
# },
|
433
|
+
# "version" => 6
|
434
|
+
# }
|
435
|
+
def stub_publishing_api_has_links(links)
|
436
|
+
links = deep_transform_keys(links, &:to_sym)
|
437
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/links/" + links[:content_id]
|
438
|
+
stub_request(:get, url).to_return(status: 200, body: links.to_json, headers: {})
|
439
|
+
end
|
440
|
+
|
441
|
+
# Stub a request to the expanded links endpoint
|
442
|
+
#
|
443
|
+
# @param [Hash] links the structure of the links hash
|
444
|
+
#
|
445
|
+
# @example
|
446
|
+
# stub_publishing_api_has_expanded_links(
|
447
|
+
# {
|
448
|
+
# "content_id" => "64aadc14-9bca-40d9-abb4-4f21f9792a05",
|
449
|
+
# "expanded_links" => {
|
450
|
+
# "mainstream_browse_pages" => [
|
451
|
+
# {
|
452
|
+
# "content_id" => "df2e7a3e-2078-45de-a76a-fd37d027427a",
|
453
|
+
# "base_path" => "/a/base/path",
|
454
|
+
# "document_type" => "mainstream_browse_page",
|
455
|
+
# "locale" => "en",
|
456
|
+
# "links" => {},
|
457
|
+
# # ...
|
458
|
+
# }
|
459
|
+
# ],
|
460
|
+
# "parent" => [
|
461
|
+
# {
|
462
|
+
# "content_id" => "df2e7a3e-2028-45de-a75a-fd37d027427e",
|
463
|
+
# "document_type" => "mainstream_browse_page",
|
464
|
+
# # ...
|
465
|
+
# },
|
466
|
+
# ]
|
467
|
+
# }
|
468
|
+
# }
|
469
|
+
# )
|
470
|
+
#
|
471
|
+
# @example
|
472
|
+
# Services.publishing_api.expanded_links("64aadc14-9bca-40d9-abb4-4f21f9792a05")
|
473
|
+
# => {
|
474
|
+
# "content_id" => "64aadc14-9bca-40d9-abb4-4f21f9792a05",
|
475
|
+
# "expanded_links" => {
|
476
|
+
# "mainstream_browse_pages" => [
|
477
|
+
# {
|
478
|
+
# "content_id" => "df2e7a3e-2078-45de-a76a-fd37d027427a",
|
479
|
+
# "base_path" => "/a/base/path",
|
480
|
+
# "document_type" => "mainstream_browse_page",
|
481
|
+
# "locale" => "en",
|
482
|
+
# "links" => {},
|
483
|
+
# ...
|
484
|
+
# }
|
485
|
+
# ],
|
486
|
+
# "parent" => [
|
487
|
+
# {
|
488
|
+
# "content_id" => "df2e7a3e-2028-45de-a75a-fd37d027427e",
|
489
|
+
# "document_type" => "mainstream_browse_page",
|
490
|
+
# ...
|
491
|
+
# },
|
492
|
+
# ]
|
493
|
+
# }
|
494
|
+
# }
|
495
|
+
def stub_publishing_api_has_expanded_links(links, with_drafts: true, generate: false)
|
496
|
+
links = deep_transform_keys(links, &:to_sym)
|
497
|
+
request_params = {}
|
498
|
+
request_params["with_drafts"] = false if !with_drafts
|
499
|
+
request_params["generate"] = true if generate
|
500
|
+
|
501
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/expanded-links/" + links[:content_id]
|
502
|
+
stub_request(:get, url)
|
503
|
+
.with(query: request_params)
|
504
|
+
.to_return(status: 200, body: links.to_json, headers: {})
|
505
|
+
end
|
506
|
+
|
507
|
+
# Stub a request to get links for content ids
|
508
|
+
#
|
509
|
+
# @param [Hash] links the links for each content id
|
510
|
+
#
|
511
|
+
# @example
|
512
|
+
# stub_publishing_api_has_links_for_content_ids(
|
513
|
+
# { "2878337b-bed9-4e7f-85b6-10ed2cbcd504" => {
|
514
|
+
# "links" => { "taxons" => ["eb6965c7-3056-45d0-ae50-2f0a5e2e0854"] }
|
515
|
+
# },
|
516
|
+
# "eec13cea-219d-4896-9c97-60114da23559" => {
|
517
|
+
# "links" => {}
|
518
|
+
# }
|
519
|
+
# }
|
520
|
+
# )
|
521
|
+
#
|
522
|
+
# @example
|
523
|
+
# Services.publishing_api.get_links_for_content_ids(["2878337b-bed9-4e7f-85b6-10ed2cbcd504"])
|
524
|
+
# => {
|
525
|
+
# "2878337b-bed9-4e7f-85b6-10ed2cbcd504" => {
|
526
|
+
# "links" => [
|
527
|
+
# "eb6965c7-3056-45d0-ae50-2f0a5e2e0854"
|
528
|
+
# ]
|
529
|
+
# }
|
530
|
+
# }
|
531
|
+
def stub_publishing_api_has_links_for_content_ids(links)
|
532
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/links/by-content-id"
|
533
|
+
stub_request(:post, url).with(body: { content_ids: links.keys }).to_return(status: 200, body: links.to_json, headers: {})
|
534
|
+
end
|
535
|
+
|
536
|
+
# Stub GET /v2/links/:content_id to return a 404 response
|
537
|
+
#
|
538
|
+
# @param content_id [UUID]
|
539
|
+
def stub_publishing_api_does_not_have_links(content_id)
|
540
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/links/" + content_id
|
541
|
+
stub_request(:get, url).to_return(status: 404, body: resource_not_found(content_id, "link set").to_json, headers: {})
|
542
|
+
end
|
543
|
+
|
544
|
+
# Stub calls to the lookups endpoint
|
545
|
+
#
|
546
|
+
# @param lookup_hash [Hash] Hash with base_path as key, content_id as value.
|
547
|
+
#
|
548
|
+
# @example
|
549
|
+
#
|
550
|
+
# stub_publishing_api_has_lookups({
|
551
|
+
# "/foo" => "51ac4247-fd92-470a-a207-6b852a97f2db",
|
552
|
+
# "/bar" => "261bd281-f16c-48d5-82d2-9544019ad9ca"
|
553
|
+
# })
|
554
|
+
#
|
555
|
+
def stub_publishing_api_has_lookups(lookup_hash)
|
556
|
+
url = PUBLISHING_API_ENDPOINT + "/lookup-by-base-path"
|
557
|
+
stub_request(:post, url).to_return(body: lookup_hash.to_json)
|
558
|
+
end
|
559
|
+
|
560
|
+
#
|
561
|
+
# Stub calls to the get linked items endpoint
|
562
|
+
#
|
563
|
+
# @param items [Array] The linked items we wish to return
|
564
|
+
# @param params [Hash] A hash of parameters
|
565
|
+
#
|
566
|
+
# @example
|
567
|
+
#
|
568
|
+
# stub_publishing_api_has_linked_items(
|
569
|
+
# [ item_1, item_2 ],
|
570
|
+
# {
|
571
|
+
# content_id: "51ac4247-fd92-470a-a207-6b852a97f2db",
|
572
|
+
# link_type: "taxons",
|
573
|
+
# fields: ["title", "description", "base_path"]
|
574
|
+
# }
|
575
|
+
# )
|
576
|
+
#
|
577
|
+
def stub_publishing_api_has_linked_items(items, params = {})
|
578
|
+
content_id = params.fetch(:content_id)
|
579
|
+
link_type = params.fetch(:link_type)
|
580
|
+
fields = params.fetch(:fields, %w(base_path content_id document_type title))
|
581
|
+
|
582
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/linked/#{content_id}"
|
583
|
+
|
584
|
+
request_parmeters = {
|
585
|
+
"fields" => fields,
|
586
|
+
"link_type" => link_type,
|
587
|
+
}
|
588
|
+
|
589
|
+
stub_request(:get, url)
|
590
|
+
.with(query: request_parmeters)
|
591
|
+
.and_return(
|
592
|
+
body: items.to_json,
|
593
|
+
status: 200,
|
594
|
+
)
|
595
|
+
end
|
596
|
+
|
597
|
+
# Stub GET /v2/editions to return a set of editions
|
598
|
+
#
|
599
|
+
# @example
|
600
|
+
#
|
601
|
+
# stub_publishing_api_get_editions(
|
602
|
+
# vehicle_recalls_and_faults, # this is a variable containing an array of editions
|
603
|
+
# fields: fields, #example: let(:fields) { %i[base_path content_id public_updated_at title publication_state] }
|
604
|
+
# per_page: 50
|
605
|
+
# )
|
606
|
+
# @param items [Array]
|
607
|
+
# @param params [Hash]
|
608
|
+
def stub_publishing_api_get_editions(editions, params = {})
|
609
|
+
url = PUBLISHING_API_V2_ENDPOINT + "/editions"
|
610
|
+
|
611
|
+
results = editions.map do |edition|
|
612
|
+
next edition unless params[:fields]
|
613
|
+
|
614
|
+
edition.select { |k| params[:fields].include?(k) }
|
615
|
+
end
|
616
|
+
|
617
|
+
per_page = (params[:per_page] || 100).to_i
|
618
|
+
results = results.take(per_page)
|
619
|
+
|
620
|
+
body = {
|
621
|
+
results: results,
|
622
|
+
links: [
|
623
|
+
{ rel: "self", href: "#{PUBLISHING_API_V2_ENDPOINT}/editions" },
|
624
|
+
],
|
625
|
+
}
|
626
|
+
|
627
|
+
stub_request(:get, url)
|
628
|
+
.with(query: params)
|
629
|
+
.to_return(status: 200, body: body.to_json, headers: {})
|
630
|
+
end
|
631
|
+
|
14
632
|
def stub_publishing_api_unreserve_path(base_path, publishing_app = /.*/)
|
15
633
|
stub_publishing_api_unreserve_path_with_code(base_path, publishing_app, 200)
|
16
634
|
end
|
@@ -34,7 +652,7 @@ module GdsApi
|
|
34
652
|
stub_request(:delete, url).to_return(status: 200, body: "{}", headers: { "Content-Type" => "application/json; charset=utf-8" })
|
35
653
|
end
|
36
654
|
|
37
|
-
def
|
655
|
+
def stub_any_publishing_api_put_intent
|
38
656
|
stub_request(:put, %r{\A#{PUBLISHING_API_ENDPOINT}/publish-intent})
|
39
657
|
end
|
40
658
|
|
@@ -71,48 +689,171 @@ module GdsApi
|
|
71
689
|
end
|
72
690
|
end
|
73
691
|
|
74
|
-
|
75
|
-
|
692
|
+
# Stub a PUT /paths/:base_path request with the given content id and request body.
|
693
|
+
#
|
694
|
+
# @example
|
695
|
+
# stub_publishing_api_path_reservation(
|
696
|
+
# my_content_id,
|
697
|
+
# publishing_app: "content-publisher",
|
698
|
+
# override_existing: true,
|
699
|
+
# )
|
700
|
+
#
|
701
|
+
# @param base_path [String]
|
702
|
+
# @param params [Hash]
|
703
|
+
def stub_publishing_api_path_reservation(base_path, params = {})
|
704
|
+
url = PUBLISHING_API_ENDPOINT + "/paths#{base_path}"
|
705
|
+
response = {
|
706
|
+
status: 200,
|
707
|
+
headers: { content_type: "application/json" },
|
708
|
+
body: params.merge(base_path: base_path).to_json,
|
709
|
+
}
|
710
|
+
|
711
|
+
stub_request(:put, url).with(body: params).to_return(response)
|
76
712
|
end
|
77
713
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
}
|
714
|
+
# Stub all PUT /paths/:base_path requests
|
715
|
+
#
|
716
|
+
# @example
|
717
|
+
# stub_any_publishing_api_path_reservation
|
718
|
+
def stub_any_publishing_api_path_reservation
|
719
|
+
stub_request(:put, %r[\A#{PUBLISHING_API_ENDPOINT}/paths/]).to_return do |request|
|
720
|
+
base_path = request.uri.path.sub(%r{\A/paths}, "")
|
721
|
+
body = JSON.parse(request.body).merge(base_path: base_path)
|
722
|
+
{
|
723
|
+
status: 200,
|
724
|
+
headers: { content_type: "application/json" },
|
725
|
+
body: body.to_json,
|
726
|
+
}
|
727
|
+
end
|
84
728
|
end
|
85
729
|
|
730
|
+
# Stub a PUT /paths/:base_path request for a particular publishing
|
731
|
+
# application. Calling for a different publishing application will return
|
732
|
+
# a 422 response.
|
733
|
+
#
|
734
|
+
# @example
|
735
|
+
# stub_publishing_api_has_path_reservation_for("/foo", "content-publisher")
|
736
|
+
#
|
737
|
+
# @param base_path [String]
|
738
|
+
# @param publishing_app [String]
|
86
739
|
def stub_publishing_api_has_path_reservation_for(path, publishing_app)
|
87
|
-
|
88
|
-
|
740
|
+
message = "#{path} is already reserved by #{publishing_app}"
|
741
|
+
error = { code: 422,
|
742
|
+
message: "Base path #{message}",
|
743
|
+
fields: { base_path: [message] } }
|
89
744
|
|
90
745
|
stub_request(:put, "#{PUBLISHING_API_ENDPOINT}/paths#{path}").
|
91
|
-
to_return(status: 422,
|
92
|
-
headers: { content_type: "application/json" }
|
746
|
+
to_return(status: 422,
|
747
|
+
headers: { content_type: "application/json" },
|
748
|
+
body: { error: error }.to_json)
|
93
749
|
|
94
750
|
stub_request(:put, "#{PUBLISHING_API_ENDPOINT}/paths#{path}").
|
95
751
|
with(body: { "publishing_app" => publishing_app }).
|
96
752
|
to_return(status: 200,
|
97
753
|
headers: { content_type: "application/json" },
|
98
|
-
body:
|
754
|
+
body: { publishing_app: publishing_app, base_path: path }.to_json)
|
99
755
|
end
|
100
756
|
|
101
|
-
|
102
|
-
|
103
|
-
|
757
|
+
# Stub a PUT /paths/:base_path request for a particular publishing
|
758
|
+
# application. Calling for a different publishing application will return
|
759
|
+
# a 422 response.
|
760
|
+
#
|
761
|
+
# @example
|
762
|
+
# stub_publishing_api_returns_path_reservation_validation_error_for(
|
763
|
+
# "/foo",
|
764
|
+
# "field" => ["error 1", "error 2"]
|
765
|
+
# )
|
766
|
+
#
|
767
|
+
# @param base_path [String]
|
768
|
+
# @param error_fields [Hash]
|
769
|
+
def stub_publishing_api_returns_path_reservation_validation_error_for(base_path, error_fields = {})
|
770
|
+
error_fields = { "base_path" => ["Computer says no"] } if error_fields.empty?
|
104
771
|
|
105
|
-
|
106
|
-
|
772
|
+
message = error_fields.keys.first.to_s.capitalize.gsub(/_/, " ") + " " +
|
773
|
+
error_fields.values.flatten.first
|
774
|
+
|
775
|
+
error = { code: 422, message: message, fields: error_fields }
|
776
|
+
|
777
|
+
stub_request(:put, "#{PUBLISHING_API_ENDPOINT}/paths#{base_path}").
|
778
|
+
to_return(status: 422,
|
779
|
+
headers: { content_type: "application/json" },
|
780
|
+
body: { error: error }.to_json)
|
107
781
|
end
|
108
782
|
|
109
783
|
# Aliases for DEPRECATED methods
|
110
784
|
alias_method :publishing_api_isnt_available, :stub_publishing_api_isnt_available
|
785
|
+
alias_method :publishing_api_has_content, :stub_publishing_api_has_content
|
786
|
+
alias_method :publishing_api_has_fields_for_document, :stub_publishing_api_has_fields_for_document
|
787
|
+
alias_method :publishing_api_has_linkables, :stub_publishing_api_has_linkables
|
788
|
+
alias_method :publishing_api_has_item, :stub_publishing_api_has_item
|
789
|
+
alias_method :publishing_api_has_item_in_sequence, :stub_publishing_api_has_item_in_sequence
|
790
|
+
alias_method :publishing_api_does_not_have_item, :stub_publishing_api_does_not_have_item
|
791
|
+
alias_method :publishing_api_has_links, :stub_publishing_api_has_links
|
792
|
+
alias_method :publishing_api_has_expanded_links, :stub_publishing_api_has_expanded_links
|
793
|
+
alias_method :publishing_api_has_links_for_content_ids, :stub_publishing_api_has_links_for_content_ids
|
794
|
+
alias_method :publishing_api_does_not_have_links, :stub_publishing_api_does_not_have_links
|
795
|
+
alias_method :publishing_api_has_lookups, :stub_publishing_api_has_lookups
|
796
|
+
alias_method :publishing_api_has_linked_items, :stub_publishing_api_has_linked_items
|
797
|
+
alias_method :publishing_api_get_editions, :stub_publishing_api_get_editions
|
111
798
|
alias_method :publishing_api_has_path_reservation_for, :stub_publishing_api_has_path_reservation_for
|
112
799
|
alias_method :publishing_api_returns_path_reservation_validation_error_for, :stub_publishing_api_returns_path_reservation_validation_error_for
|
800
|
+
alias_method :stub_default_publishing_api_path_reservation, :stub_any_publishing_api_path_reservation
|
801
|
+
alias_method :stub_default_publishing_api_put_intent, :stub_any_publishing_api_put_intent
|
113
802
|
|
114
803
|
private
|
115
804
|
|
805
|
+
def stub_publishing_api_put(*args)
|
806
|
+
stub_publishing_api_postlike_call(:put, *args)
|
807
|
+
end
|
808
|
+
|
809
|
+
def stub_publishing_api_patch(*args)
|
810
|
+
stub_publishing_api_postlike_call(:patch, *args)
|
811
|
+
end
|
812
|
+
|
813
|
+
def stub_publishing_api_postlike_call(method, content_id, body, resource_path, override_response_hash = {})
|
814
|
+
response_hash = { status: 200, body: "{}", headers: { "Content-Type" => "application/json; charset=utf-8" } }
|
815
|
+
response_hash.merge!(override_response_hash)
|
816
|
+
response_hash[:body] = response_hash[:body].to_json if response_hash[:body].is_a?(Hash)
|
817
|
+
url = PUBLISHING_API_V2_ENDPOINT + resource_path + "/" + content_id
|
818
|
+
stub_request(method, url).with(body: body).to_return(response_hash)
|
819
|
+
end
|
820
|
+
|
821
|
+
def deep_stringify_keys(hash)
|
822
|
+
deep_transform_keys(hash, &:to_s)
|
823
|
+
end
|
824
|
+
|
825
|
+
def deep_transform_keys(object, &block)
|
826
|
+
case object
|
827
|
+
when Hash
|
828
|
+
object.each_with_object({}) do |(key, value), result|
|
829
|
+
result[yield(key)] = deep_transform_keys(value, &block)
|
830
|
+
end
|
831
|
+
when Array
|
832
|
+
object.map { |item| deep_transform_keys(item, &block) }
|
833
|
+
else
|
834
|
+
object
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
def resource_not_found(content_id, type)
|
839
|
+
{
|
840
|
+
error: {
|
841
|
+
code: 404,
|
842
|
+
message: "Could not find #{type} with content_id: #{content_id}",
|
843
|
+
},
|
844
|
+
}
|
845
|
+
end
|
846
|
+
|
847
|
+
def version_conflict(expected_version, actual_version = expected_version + 1)
|
848
|
+
{
|
849
|
+
error: {
|
850
|
+
code: 409,
|
851
|
+
message: "A lock-version conflict occurred. The `previous_version` you've sent (#{expected_version}) is not the same as the current lock version of the edition (#{actual_version}).",
|
852
|
+
fields: { previous_version: ["does not match"] },
|
853
|
+
},
|
854
|
+
}
|
855
|
+
end
|
856
|
+
|
116
857
|
def stub_publishing_api_unreserve_path_with_code(base_path, publishing_app, code)
|
117
858
|
url = PUBLISHING_API_ENDPOINT + "/paths" + base_path
|
118
859
|
body = { publishing_app: publishing_app }
|
@@ -147,16 +888,6 @@ module GdsApi
|
|
147
888
|
def intent_for_publishing_api(base_path, publishing_app = "publisher")
|
148
889
|
intent_for_base_path(base_path).merge("publishing_app" => publishing_app)
|
149
890
|
end
|
150
|
-
|
151
|
-
def publishing_api_path_data_for(path, override_attributes = {})
|
152
|
-
now = Time.zone.now.utc.iso8601
|
153
|
-
{
|
154
|
-
"path" => path,
|
155
|
-
"publishing_app" => "foo-publisher",
|
156
|
-
"created_at" => now,
|
157
|
-
"updated_at" => now,
|
158
|
-
}.merge(override_attributes)
|
159
|
-
end
|
160
891
|
end
|
161
892
|
end
|
162
893
|
end
|