Skip to content

Commit c9bb25d

Browse files
authored
Merge pull request #98 from alphagov/refac-doc-3
Extract content/metadata logic into concern
2 parents 1926fbd + ffd4c7d commit c9bb25d

4 files changed

Lines changed: 143 additions & 136 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module PublishingApi
2+
module Content
3+
# All the possible keys in the message hash that can contain the primary unstructured document
4+
# content that we want to index, represented as JsonPath path strings.
5+
INDEXABLE_CONTENT_VALUES_JSON_PATHS = %w[
6+
$.details.description
7+
$.details.introduction
8+
$.details.introductory_paragraph
9+
$.details.contact_groups[*].title
10+
$.details.title
11+
$.details.summary
12+
$.details.body
13+
$.details.need_to_know
14+
$.details.more_information
15+
].map { JsonPath.new(_1, use_symbols: true) }.freeze
16+
INDEXABLE_CONTENT_SEPARATOR = "\n".freeze
17+
18+
# Extracts a single string of indexable unstructured content from the document.
19+
def content
20+
values_from_json_paths = INDEXABLE_CONTENT_VALUES_JSON_PATHS.map { _1.on(document_hash) }
21+
values_from_parts = document_hash.dig(:details, :parts)&.map do
22+
# Add the part title as a heading to help the search model better understand the structure
23+
# of the content
24+
["<h1>#{_1[:title]}</h1>", ContentWithMultipleTypes.new(_1[:body]).html_content]
25+
end
26+
27+
[
28+
*values_from_json_paths,
29+
*values_from_parts,
30+
].flatten.join(INDEXABLE_CONTENT_SEPARATOR)
31+
end
32+
end
33+
end
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
module PublishingApi
2+
module Metadata
3+
# All the possible keys in the message hash that can contain additional keywords or other text
4+
# that should be searchable but doesn't form part of the primary document content, represented
5+
# as JsonPath path strings.
6+
ADDITIONAL_SEARCHABLE_TEXT_VALUES_JSON_PATHS = %w[
7+
$.details.hidden_search_terms
8+
$.details.metadata.hidden_indexable_content
9+
$.details.metadata.project_code
10+
$.details.metadata.aircraft_type
11+
$.details.metadata.registration
12+
$.details.metadata.tribunal_decision_categories_name
13+
$.details.metadata.tribunal_decision_country_name
14+
$.details.metadata.tribunal_decision_judges_name
15+
$.details.metadata.tribunal_decision_category_name
16+
$.details.metadata.tribunal_decision_sub_category_name
17+
$.details.metadata.tribunal_decision_sub_categories_name
18+
$.details.metadata.tribunal_decision_landmark_name
19+
$.details.acronym
20+
$.details.attachments[*]['title','isbn','unique_reference','command_paper_number','hoc_paper_number']
21+
].map { JsonPath.new(_1, use_symbols: true) }.freeze
22+
ADDITIONAL_SEARCHABLE_TEXT_VALUES_SEPARATOR = "\n".freeze
23+
24+
# Extracts a hash of structured metadata about this document.
25+
def metadata
26+
{
27+
content_id: document_hash[:content_id],
28+
title: document_hash[:title],
29+
description: document_hash[:description],
30+
additional_searchable_text:,
31+
link:,
32+
url:,
33+
public_timestamp:,
34+
document_type: document_hash[:document_type],
35+
content_purpose_supergroup: document_hash[:content_purpose_supergroup],
36+
part_of_taxonomy_tree: document_hash.dig(:links, :taxons) || [],
37+
# Vertex can only currently boost on numeric fields, not booleans
38+
is_historic: historic? ? 1 : 0,
39+
government_name:,
40+
organisation_state:,
41+
locale: document_hash[:locale],
42+
parts:,
43+
}.compact
44+
end
45+
46+
def link
47+
document_hash[:base_path].presence || document_hash.dig(:details, :url)
48+
end
49+
50+
def link_relative?
51+
link&.start_with?("/")
52+
end
53+
54+
def url
55+
return link unless link_relative?
56+
57+
Plek.website_root + link
58+
end
59+
60+
def additional_searchable_text
61+
values = ADDITIONAL_SEARCHABLE_TEXT_VALUES_JSON_PATHS.map { _1.on(document_hash) }
62+
values
63+
.flatten
64+
.compact_blank
65+
.join(ADDITIONAL_SEARCHABLE_TEXT_VALUES_SEPARATOR)
66+
end
67+
68+
def public_timestamp
69+
return nil unless document_hash[:public_updated_at]
70+
71+
# rubocop:disable Rails/TimeZone (string already contains timezone info which would be lost)
72+
Time.parse(document_hash[:public_updated_at]).to_i
73+
# rubocop:enable Rails/TimeZone
74+
end
75+
76+
def historic?
77+
political = document_hash.dig(:details, :political) || false
78+
government = document_hash.dig(:expanded_links, :government)&.first
79+
80+
political && government&.dig(:details, :current) == false
81+
end
82+
83+
def government_name
84+
document_hash
85+
.dig(:expanded_links, :government)
86+
&.first
87+
&.dig(:title)
88+
end
89+
90+
def organisation_state
91+
document_hash
92+
.dig(:details, :organisation_govuk_status, :status)
93+
end
94+
95+
def parts
96+
document_hash
97+
.dig(:details, :parts)
98+
&.map do
99+
{
100+
slug: _1[:slug],
101+
title: _1[:title],
102+
body: ContentWithMultipleTypes.new(_1[:body]).summarized_text_content,
103+
}
104+
end
105+
end
106+
end
107+
end

app/models/publishing_api_action/content_with_multiple_types.rb renamed to app/models/publishing_api/content_with_multiple_types.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module PublishingApiAction
1+
module PublishingApi
22
class ContentWithMultipleTypes
33
def initialize(content_with_multiple_types)
44
@content_with_multiple_types = content_with_multiple_types
Lines changed: 2 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,11 @@
11
module PublishingApiAction
22
class Publish < Base
3-
# All the possible keys in the message hash that can contain the primary unstructured document
4-
# content that we want to index, represented as JsonPath path strings.
5-
INDEXABLE_CONTENT_VALUES_JSON_PATHS = %w[
6-
$.details.description
7-
$.details.introduction
8-
$.details.introductory_paragraph
9-
$.details.contact_groups[*].title
10-
$.details.title
11-
$.details.summary
12-
$.details.body
13-
$.details.need_to_know
14-
$.details.more_information
15-
].map { JsonPath.new(_1, use_symbols: true) }.freeze
16-
INDEXABLE_CONTENT_SEPARATOR = "\n".freeze
17-
18-
# All the possible keys in the message hash that can contain additional keywords or other text
19-
# that should be searchable but doesn't form part of the primary document content, represented
20-
# as JsonPath path strings.
21-
ADDITIONAL_SEARCHABLE_TEXT_VALUES_JSON_PATHS = %w[
22-
$.details.hidden_search_terms
23-
$.details.metadata.hidden_indexable_content
24-
$.details.metadata.project_code
25-
$.details.metadata.aircraft_type
26-
$.details.metadata.registration
27-
$.details.metadata.tribunal_decision_categories_name
28-
$.details.metadata.tribunal_decision_country_name
29-
$.details.metadata.tribunal_decision_judges_name
30-
$.details.metadata.tribunal_decision_category_name
31-
$.details.metadata.tribunal_decision_sub_category_name
32-
$.details.metadata.tribunal_decision_sub_categories_name
33-
$.details.metadata.tribunal_decision_landmark_name
34-
$.details.acronym
35-
$.details.attachments[*]['title','isbn','unique_reference','command_paper_number','hoc_paper_number']
36-
].map { JsonPath.new(_1, use_symbols: true) }.freeze
37-
ADDITIONAL_SEARCHABLE_TEXT_VALUES_SEPARATOR = "\n".freeze
3+
include ::PublishingApi::Metadata
4+
include ::PublishingApi::Content
385

396
# Synchronize the document to the given service (i.e. create or update it remotely)
407
def synchronize(service: DiscoveryEngine::Put.new)
418
service.call(content_id, metadata, content:, payload_version:)
429
end
43-
44-
# Extracts a hash of structured metadata about this document.
45-
def metadata
46-
{
47-
content_id: document_hash[:content_id],
48-
title: document_hash[:title],
49-
description: document_hash[:description],
50-
additional_searchable_text:,
51-
link:,
52-
url:,
53-
public_timestamp:,
54-
document_type: document_hash[:document_type],
55-
content_purpose_supergroup: document_hash[:content_purpose_supergroup],
56-
part_of_taxonomy_tree: document_hash.dig(:links, :taxons) || [],
57-
# Vertex can only currently boost on numeric fields, not booleans
58-
is_historic: historic? ? 1 : 0,
59-
government_name:,
60-
organisation_state:,
61-
locale: document_hash[:locale],
62-
parts:,
63-
}.compact
64-
end
65-
66-
# Extracts a single string of indexable unstructured content from the document.
67-
def content
68-
values_from_json_paths = INDEXABLE_CONTENT_VALUES_JSON_PATHS.map { _1.on(document_hash) }
69-
values_from_parts = document_hash.dig(:details, :parts)&.map do
70-
# Add the part title as a heading to help the search model better understand the structure
71-
# of the content
72-
["<h1>#{_1[:title]}</h1>", ContentWithMultipleTypes.new(_1[:body]).html_content]
73-
end
74-
75-
[
76-
*values_from_json_paths,
77-
*values_from_parts,
78-
].flatten.join(INDEXABLE_CONTENT_SEPARATOR)
79-
end
80-
81-
private
82-
83-
def link
84-
document_hash[:base_path].presence || document_hash.dig(:details, :url)
85-
end
86-
87-
def link_relative?
88-
link&.start_with?("/")
89-
end
90-
91-
def url
92-
return link unless link_relative?
93-
94-
Plek.website_root + link
95-
end
96-
97-
def additional_searchable_text
98-
values = ADDITIONAL_SEARCHABLE_TEXT_VALUES_JSON_PATHS.map { _1.on(document_hash) }
99-
values
100-
.flatten
101-
.compact_blank
102-
.join(ADDITIONAL_SEARCHABLE_TEXT_VALUES_SEPARATOR)
103-
end
104-
105-
def public_timestamp
106-
return nil unless document_hash[:public_updated_at]
107-
108-
# rubocop:disable Rails/TimeZone (string already contains timezone info which would be lost)
109-
Time.parse(document_hash[:public_updated_at]).to_i
110-
# rubocop:enable Rails/TimeZone
111-
end
112-
113-
def historic?
114-
political = document_hash.dig(:details, :political) || false
115-
government = document_hash.dig(:expanded_links, :government)&.first
116-
117-
political && government&.dig(:details, :current) == false
118-
end
119-
120-
def government_name
121-
document_hash
122-
.dig(:expanded_links, :government)
123-
&.first
124-
&.dig(:title)
125-
end
126-
127-
def organisation_state
128-
document_hash
129-
.dig(:details, :organisation_govuk_status, :status)
130-
end
131-
132-
def parts
133-
document_hash
134-
.dig(:details, :parts)
135-
&.map do
136-
{
137-
slug: _1[:slug],
138-
title: _1[:title],
139-
body: ContentWithMultipleTypes.new(_1[:body]).summarized_text_content,
140-
}
141-
end
142-
end
14310
end
14411
end

0 commit comments

Comments
 (0)