publishing_platform_api_adapters 0.7.1 → 0.8.1
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12a639bdc05f05fbcb78557b20924d4d95286b09af685f76f5e2b6989d998bd7
|
4
|
+
data.tar.gz: '0674539db2157aac06598a56fe898cbcb1ce4baa847f2bef637d62dbe4947501'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19667cbc60807f1d7c3fe54eb1ab0a8bd5437fe328f011cd5fc8e1bfa13085218c84bd80a146c645a18cc65af8ddef2dceec9b14a46f689508be7abe737b16c3
|
7
|
+
data.tar.gz: e77e8a1bd9b420c84dfdbf09bcbee8d672eab10f27422a14d6a0568572f0f8286e4a8b11cc25969a70d3e95c67bcde71c46cc55851bdb6c57070c47550e8c6f7
|
@@ -16,9 +16,96 @@ class PublishingPlatformApi::ContentStore < PublishingPlatformApi::Base
|
|
16
16
|
raise ItemNotFound.build_from(e)
|
17
17
|
end
|
18
18
|
|
19
|
+
# Returns an array tuple of destination url with status code e.g
|
20
|
+
# ["https://www.publishing-platform.co.uk/destination", 301]
|
21
|
+
def self.redirect_for_path(content_item, request_path, request_query = "")
|
22
|
+
RedirectResolver.call(content_item, request_path, request_query)
|
23
|
+
end
|
24
|
+
|
19
25
|
private
|
20
26
|
|
21
27
|
def content_item_url(base_path)
|
22
28
|
"#{endpoint}/content#{base_path}"
|
23
29
|
end
|
30
|
+
|
31
|
+
class RedirectResolver
|
32
|
+
def initialize(content_item, request_path, request_query = "")
|
33
|
+
@content_item = content_item
|
34
|
+
@request_path = request_path
|
35
|
+
@request_query = request_query.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.call(*args)
|
39
|
+
new(*args).call
|
40
|
+
end
|
41
|
+
|
42
|
+
def call
|
43
|
+
redirect = redirect_for_path(request_path)
|
44
|
+
raise UnresolvedRedirect, "Could not find a matching redirect" unless redirect
|
45
|
+
|
46
|
+
destination_uri = URI.parse(
|
47
|
+
resolve_destination(redirect, request_path, request_query),
|
48
|
+
)
|
49
|
+
|
50
|
+
url = if destination_uri.absolute?
|
51
|
+
destination_uri.to_s
|
52
|
+
else
|
53
|
+
"#{PublishingPlatformLocation.new.website_root}#{destination_uri}"
|
54
|
+
end
|
55
|
+
|
56
|
+
[url, 301]
|
57
|
+
end
|
58
|
+
|
59
|
+
private_class_method :new
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
attr_reader :content_item, :request_path, :request_query
|
64
|
+
|
65
|
+
def redirect_for_path(path)
|
66
|
+
redirects_by_segments.find do |r|
|
67
|
+
next true if r["path"] == path
|
68
|
+
|
69
|
+
route_prefix_match?(r["path"], path) if r["type"] == "prefix"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def redirects_by_segments
|
74
|
+
redirects = content_item["redirects"] || []
|
75
|
+
redirects.sort_by { |r| r["path"].split("/").count * -1 }
|
76
|
+
end
|
77
|
+
|
78
|
+
def route_prefix_match?(prefix_path, path_to_match)
|
79
|
+
prefix_regex = %r{^#{Regexp.escape(prefix_path)}/}
|
80
|
+
path_to_match.match prefix_regex
|
81
|
+
end
|
82
|
+
|
83
|
+
def resolve_destination(redirect, path, query)
|
84
|
+
return redirect["destination"] unless redirect["segments_mode"] == "preserve"
|
85
|
+
|
86
|
+
if redirect["type"] == "prefix"
|
87
|
+
prefix_destination(redirect, path, query)
|
88
|
+
else
|
89
|
+
redirect["destination"] + (query.empty? ? "" : "?#{query}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def prefix_destination(redirect, path, query)
|
94
|
+
uri = URI.parse(redirect["destination"])
|
95
|
+
start_char = redirect["path"].length
|
96
|
+
suffix = path[start_char..]
|
97
|
+
|
98
|
+
if uri.path == "" && suffix[0] != "/"
|
99
|
+
uri.path = "/#{suffix}"
|
100
|
+
else
|
101
|
+
uri.path += suffix
|
102
|
+
end
|
103
|
+
|
104
|
+
uri.query = query if uri.query.nil? && !query.empty?
|
105
|
+
|
106
|
+
uri.to_s
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class UnresolvedRedirect < PublishingPlatformApi::BaseError; end
|
24
111
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module PublishingPlatformApi
|
2
|
+
module TestHelpers
|
3
|
+
module ContentItemHelpers
|
4
|
+
def content_item_for_base_path(base_path)
|
5
|
+
{
|
6
|
+
"title" => titleize_base_path(base_path),
|
7
|
+
"description" => "Description for #{base_path}",
|
8
|
+
"schema_name" => "answer",
|
9
|
+
"document_type" => "answer",
|
10
|
+
"public_updated_at" => "2014-05-06T12:01:00+00:00",
|
11
|
+
# base_path is added in as necessary (ie for content-store GET responses)
|
12
|
+
# "base_path" => base_path,
|
13
|
+
"details" => {
|
14
|
+
"body" => "Some content for #{base_path}",
|
15
|
+
},
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def gone_content_item_for_base_path(base_path)
|
20
|
+
{
|
21
|
+
"title" => nil,
|
22
|
+
"description" => nil,
|
23
|
+
"document_type" => "gone",
|
24
|
+
"schema_name" => "gone",
|
25
|
+
"public_updated_at" => nil,
|
26
|
+
"base_path" => base_path,
|
27
|
+
"withdrawn_notice" => {},
|
28
|
+
"details" => {},
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def titleize_base_path(base_path, options = {})
|
33
|
+
if options[:title_case]
|
34
|
+
base_path.tr("-", " ").gsub(/\b./, &:upcase)
|
35
|
+
else
|
36
|
+
base_path.gsub(%r{[-/]}, " ").strip.capitalize
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "publishing_platform_api/test_helpers/content_item_helpers"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module PublishingPlatformApi
|
5
|
+
module TestHelpers
|
6
|
+
module ContentStore
|
7
|
+
include ContentItemHelpers
|
8
|
+
|
9
|
+
def content_store_endpoint(draft: false)
|
10
|
+
draft ? PublishingPlatformLocation.find("draft-content-store") : PublishingPlatformLocation.find("content-store")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Stubs a content item in the content store.
|
14
|
+
# The following options can be passed in:
|
15
|
+
#
|
16
|
+
# :max_age will set the max-age of the Cache-Control header in the response. Defaults to 900
|
17
|
+
# :private if true, the Cache-Control header will include the "private" directive. By default it
|
18
|
+
# will include "public"
|
19
|
+
# :draft will point to the draft content store if set to true
|
20
|
+
def stub_content_store_has_item(base_path, body = content_item_for_base_path(base_path), options = {})
|
21
|
+
max_age = options.fetch(:max_age, 900)
|
22
|
+
visibility = options[:private] ? "private" : "public"
|
23
|
+
body = body.to_json unless body.is_a?(String)
|
24
|
+
|
25
|
+
endpoint = content_store_endpoint(draft: options[:draft])
|
26
|
+
stub_request(:get, "#{endpoint}/content#{base_path}").to_return(
|
27
|
+
status: 200,
|
28
|
+
body:,
|
29
|
+
headers: {
|
30
|
+
cache_control: "#{visibility}, max-age=#{max_age}",
|
31
|
+
date: Time.now.httpdate,
|
32
|
+
},
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def stub_content_store_does_not_have_item(base_path, options = {})
|
37
|
+
endpoint = content_store_endpoint(draft: options[:draft])
|
38
|
+
stub_request(:get, "#{endpoint}/content#{base_path}").to_return(status: 404, headers: {})
|
39
|
+
end
|
40
|
+
|
41
|
+
# Content store has gone item
|
42
|
+
#
|
43
|
+
# Stubs a content item in the content store to respond with 410 HTTP Status Code and response body with 'format' set to 'gone'.
|
44
|
+
#
|
45
|
+
# @param base_path [String]
|
46
|
+
# @param body [Hash]
|
47
|
+
# @param options [Hash]
|
48
|
+
# @option options [String] draft Will point to the draft content store if set to true
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
#
|
52
|
+
# stub_content_store.stub_content_store_has_gone_item('/sample-slug')
|
53
|
+
#
|
54
|
+
# # Will return HTTP Status Code 410 and the following response body:
|
55
|
+
# {
|
56
|
+
# "title" => nil,
|
57
|
+
# "description" => nil,
|
58
|
+
# "format" => "gone",
|
59
|
+
# "schema_name" => "gone",
|
60
|
+
# "public_updated_at" => nil,
|
61
|
+
# "base_path" => "/sample-slug",
|
62
|
+
# "withdrawn_notice" => {},
|
63
|
+
# "details" => {}
|
64
|
+
# }
|
65
|
+
def stub_content_store_has_gone_item(base_path, body = gone_content_item_for_base_path(base_path), options = {})
|
66
|
+
body = body.to_json unless body.is_a?(String)
|
67
|
+
endpoint = content_store_endpoint(draft: options[:draft])
|
68
|
+
stub_request(:get, "#{endpoint}/content#{base_path}").to_return(
|
69
|
+
status: 410,
|
70
|
+
body:,
|
71
|
+
headers: {},
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def stub_content_store_isnt_available
|
76
|
+
stub_request(:any, /#{content_store_endpoint}\/.*/).to_return(status: 503)
|
77
|
+
end
|
78
|
+
|
79
|
+
def content_item_for_base_path(base_path)
|
80
|
+
super.merge("base_path" => base_path)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: publishing_platform_api_adapters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Publishing Platform
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: addressable
|
@@ -114,6 +114,8 @@ files:
|
|
114
114
|
- lib/publishing_platform_api/railtie.rb
|
115
115
|
- lib/publishing_platform_api/response.rb
|
116
116
|
- lib/publishing_platform_api/router.rb
|
117
|
+
- lib/publishing_platform_api/test_helpers/content_item_helpers.rb
|
118
|
+
- lib/publishing_platform_api/test_helpers/content_store.rb
|
117
119
|
- lib/publishing_platform_api/version.rb
|
118
120
|
- lib/publishing_platform_api_adapters.rb
|
119
121
|
licenses:
|
@@ -133,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
135
|
- !ruby/object:Gem::Version
|
134
136
|
version: '0'
|
135
137
|
requirements: []
|
136
|
-
rubygems_version: 3.6.
|
138
|
+
rubygems_version: 3.6.7
|
137
139
|
specification_version: 4
|
138
140
|
summary: Adapters to work with Publishing Platform APIs
|
139
141
|
test_files: []
|