govuk_content_models 29.1.1 → 29.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/app/models/artefact.rb +12 -0
- data/app/models/prerendered_entity.rb +13 -0
- data/app/models/rendered_manual.rb +17 -0
- data/app/models/rendered_specialist_document.rb +19 -0
- data/app/validators/slug_validator.rb +59 -0
- data/lib/govuk_content_models/test_helpers/factories.rb +19 -0
- data/lib/govuk_content_models/version.rb +1 -1
- data/test/fixtures/specialist_document_fixtures.rb +16 -0
- data/test/models/artefact_test.rb +9 -0
- data/test/models/prerendered_entity_tests.rb +46 -0
- data/test/models/rendered_manual_test.rb +10 -0
- data/test/models/rendered_specialist_document_test.rb +12 -0
- data/test/validators/slug_validator_test.rb +26 -0
- metadata +12 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab1abf4484762f870e3d8e538b706e5cd426a66d
|
4
|
+
data.tar.gz: b6545c3d24622aaf2b7d912bec0612063dc7efad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e6a87f32f108d5ad7fde9fbcd35a962ff99f15cc93fddb9bc72fb02e8ef3b10f7a803eb6d30c2be0da930b434a125e6313188a13509fc43041a2de2ca965be1
|
7
|
+
data.tar.gz: d264ff8d7bdca85773d58504fcd3e2e4dbafc09df865638bad3386e0715bea87e779ce8e227eca83c8b93443fd2f8d17262699afcc1ad2267b07ac8f9e237d87
|
data/CHANGELOG.md
CHANGED
data/app/models/artefact.rb
CHANGED
@@ -37,6 +37,7 @@ class Artefact
|
|
37
37
|
field "publication_id", type: String
|
38
38
|
field "description", type: String
|
39
39
|
field "state", type: String, default: "draft"
|
40
|
+
field "specialist_body", type: String
|
40
41
|
field "language", type: String, default: "en"
|
41
42
|
field "need_extended_font", type: Boolean, default: false
|
42
43
|
field "latest_change_note", type: String
|
@@ -74,6 +75,17 @@ class Artefact
|
|
74
75
|
"smartanswers" => ["smart-answer"],
|
75
76
|
"custom-application" => ["custom-application"], # In this case the owning_app is overriden. eg calendars, licencefinder
|
76
77
|
"travel-advice-publisher" => ["travel-advice"],
|
78
|
+
"specialist-publisher" => ["aaib_report",
|
79
|
+
"cma_case",
|
80
|
+
"countryside_stewardship_grant",
|
81
|
+
"drug_safety_update",
|
82
|
+
"european_structural_investment_fund",
|
83
|
+
"international_development_fund",
|
84
|
+
"maib_report",
|
85
|
+
"manual",
|
86
|
+
"medical_safety_alert",
|
87
|
+
"raib_report",
|
88
|
+
"vehicle_recalls_and_faults_alert"],
|
77
89
|
"finder-api" => ["finder",
|
78
90
|
"finder_email_signup"],
|
79
91
|
"whitehall" => ["announcement",
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PrerenderedEntity
|
2
|
+
def create_or_update_by_slug!(attributes)
|
3
|
+
find_or_initialize_by(
|
4
|
+
slug: attributes.fetch(:slug)
|
5
|
+
).tap do |doc|
|
6
|
+
doc.update_attributes!(attributes)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def find_by_slug(slug)
|
11
|
+
where(slug: slug).first
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "prerendered_entity"
|
2
|
+
|
3
|
+
class RenderedManual
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongoid::Timestamps
|
6
|
+
extend PrerenderedEntity
|
7
|
+
|
8
|
+
field :manual_id, type: String
|
9
|
+
field :slug, type: String
|
10
|
+
field :title, type: String
|
11
|
+
field :summary, type: String
|
12
|
+
field :section_groups, type: Array
|
13
|
+
|
14
|
+
index "slug", unique: true
|
15
|
+
|
16
|
+
validates_uniqueness_of :slug
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "prerendered_entity"
|
2
|
+
|
3
|
+
class RenderedSpecialistDocument
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongoid::Timestamps
|
6
|
+
extend PrerenderedEntity
|
7
|
+
|
8
|
+
field :slug, type: String
|
9
|
+
field :title, type: String
|
10
|
+
field :summary, type: String
|
11
|
+
field :body, type: String
|
12
|
+
field :published_at, type: DateTime
|
13
|
+
|
14
|
+
field :details, type: Hash
|
15
|
+
|
16
|
+
index "slug", unique: true
|
17
|
+
|
18
|
+
validates :slug, uniqueness: true
|
19
|
+
end
|
@@ -7,6 +7,8 @@ class SlugValidator < ActiveModel::EachValidator
|
|
7
7
|
HelpPageValidator,
|
8
8
|
FinderEmailSignupValidator,
|
9
9
|
GovernmentPageValidator,
|
10
|
+
ManualPageValidator,
|
11
|
+
SpecialistDocumentPageValidator,
|
10
12
|
BrowsePageValidator,
|
11
13
|
DetailedGuideValidator,
|
12
14
|
DefaultValidator
|
@@ -115,6 +117,63 @@ protected
|
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
120
|
+
class ManualPageValidator < InstanceValidator
|
121
|
+
def applicable?
|
122
|
+
of_kind?('manual')
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate!
|
126
|
+
validate_number_of_parts!
|
127
|
+
validate_guidance_prefix!
|
128
|
+
validate_parts_as_slugs!
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def validate_number_of_parts!
|
133
|
+
unless [2, 3].include?(url_parts.size)
|
134
|
+
record.errors[attribute] << 'must contains two or three path parts'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_guidance_prefix!
|
139
|
+
unless starts_with?('guidance/')
|
140
|
+
record.errors[attribute] << 'must have a guidance/ prefix'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def validate_parts_as_slugs!
|
145
|
+
unless url_parts.all? { |url_part| valid_slug?(url_part) }
|
146
|
+
record.errors[attribute] << 'must be usable in a URL'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class SpecialistDocumentPageValidator < InstanceValidator
|
152
|
+
def applicable?
|
153
|
+
of_kind?(acceptable_formats)
|
154
|
+
end
|
155
|
+
|
156
|
+
def validate!
|
157
|
+
unless url_parts.size == 2
|
158
|
+
record.errors[attribute] << "must be of form <finder-slug>/<specialist-document-slug>"
|
159
|
+
end
|
160
|
+
unless url_parts.all? { |url_part| valid_slug?(url_part) }
|
161
|
+
record.errors[attribute] << "must be usable in a URL"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
def acceptable_formats
|
167
|
+
Artefact::FORMATS_BY_DEFAULT_OWNING_APP["specialist-publisher"] - unacceptable_formats
|
168
|
+
end
|
169
|
+
|
170
|
+
def unacceptable_formats
|
171
|
+
[
|
172
|
+
"manual",
|
173
|
+
]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
118
177
|
class BrowsePageValidator < InstanceValidator
|
119
178
|
def applicable?
|
120
179
|
of_kind?('specialist_sector')
|
@@ -252,6 +252,25 @@ FactoryGirl.define do
|
|
252
252
|
end
|
253
253
|
end
|
254
254
|
|
255
|
+
factory :rendered_specialist_document do
|
256
|
+
sequence(:slug) {|n| "test-rendered-specialist-document-#{n}" }
|
257
|
+
sequence(:title) {|n| "Test Rendered Specialist Document #{n}" }
|
258
|
+
summary "My summary"
|
259
|
+
body "<p>My body</p>"
|
260
|
+
details({
|
261
|
+
"opened_date" => "2013-04-20",
|
262
|
+
"market_sector" => "some-market-sector",
|
263
|
+
"case_type" => "a-case-type",
|
264
|
+
"case_state" => "open",
|
265
|
+
})
|
266
|
+
end
|
267
|
+
|
268
|
+
factory :rendered_manual do
|
269
|
+
sequence(:slug) {|n| "test-rendered-manual-#{n}" }
|
270
|
+
sequence(:title) {|n| "Test Rendered Manual #{n}" }
|
271
|
+
summary "My summary"
|
272
|
+
end
|
273
|
+
|
255
274
|
factory :simple_smart_answer_edition, :parent => :edition, :class => "SimpleSmartAnswerEdition" do
|
256
275
|
title "Simple smart answer"
|
257
276
|
body "Introduction to the smart answer"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SpecialistDocumentFixtures
|
2
|
+
def basic_specialist_document_fields
|
3
|
+
{
|
4
|
+
slug: 'cma-cases/merger-investigation-2014',
|
5
|
+
title: "Merger Investigation 2014",
|
6
|
+
summary: "This is the summary of stuff going on in the Merger Investigation 2014",
|
7
|
+
state: "published",
|
8
|
+
body: "A body",
|
9
|
+
opened_date: '2012-04-21',
|
10
|
+
document_id: 'a-document-id',
|
11
|
+
market_sector: 'oil-and-gas',
|
12
|
+
case_type: 'some-case-type',
|
13
|
+
case_state: 'open'
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
@@ -424,6 +424,15 @@ class ArtefactTest < ActiveSupport::TestCase
|
|
424
424
|
assert artefact.any_editions_published?
|
425
425
|
end
|
426
426
|
|
427
|
+
test "should have a specialist_body field present for markdown content" do
|
428
|
+
artefact = Artefact.create!(slug: "parent", name: "Harry Potter", kind: "guide", owning_app: "x")
|
429
|
+
refute_includes artefact.attributes, "specialist_body"
|
430
|
+
|
431
|
+
artefact.specialist_body = "Something wicked this way comes"
|
432
|
+
assert_includes artefact.attributes, "specialist_body"
|
433
|
+
assert_equal "Something wicked this way comes", artefact.specialist_body
|
434
|
+
end
|
435
|
+
|
427
436
|
test "should have 'video' as a supported FORMAT" do
|
428
437
|
assert_includes Artefact::FORMATS, "video"
|
429
438
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# include in a test class and define a #model_class instance method
|
2
|
+
|
3
|
+
module PrerenderedEntityTests
|
4
|
+
def test_duplicate_slug_not_allowed
|
5
|
+
model_class.create(slug: "my-slug")
|
6
|
+
second = model_class.create(slug: "my-slug")
|
7
|
+
|
8
|
+
refute second.valid?
|
9
|
+
assert_equal 1, model_class.count
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_has_no_govspeak_fields
|
13
|
+
refute model_class.const_defined?(:GOVSPEAK_FIELDS)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_create_or_update_by_slug
|
17
|
+
slug = "a-slug"
|
18
|
+
original_body = "Original body"
|
19
|
+
|
20
|
+
version1_attrs= {
|
21
|
+
slug: slug,
|
22
|
+
body: original_body,
|
23
|
+
}
|
24
|
+
|
25
|
+
created = model_class.create_or_update_by_slug!(version1_attrs)
|
26
|
+
|
27
|
+
assert created.is_a?(model_class)
|
28
|
+
assert created.persisted?
|
29
|
+
|
30
|
+
version2_attrs = version1_attrs.merge(
|
31
|
+
body: "Updated body",
|
32
|
+
)
|
33
|
+
|
34
|
+
version2 = model_class.create_or_update_by_slug!(version2_attrs)
|
35
|
+
|
36
|
+
assert version2.persisted?
|
37
|
+
assert_equal "Updated body", version2.body
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_find_by_slug
|
41
|
+
created = model_class.create!(slug: "find-by-this-slug")
|
42
|
+
found = model_class.find_by_slug("find-by-this-slug")
|
43
|
+
|
44
|
+
assert_equal created, found
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "fixtures/specialist_document_fixtures"
|
3
|
+
require "models/prerendered_entity_tests"
|
4
|
+
|
5
|
+
class RenderedSpecialistDocumentTest < ActiveSupport::TestCase
|
6
|
+
include SpecialistDocumentFixtures
|
7
|
+
include PrerenderedEntityTests
|
8
|
+
|
9
|
+
def model_class
|
10
|
+
RenderedSpecialistDocument
|
11
|
+
end
|
12
|
+
end
|
@@ -76,6 +76,16 @@ class SlugTest < ActiveSupport::TestCase
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
context "Specialist documents" do
|
80
|
+
should "all url nested one level deep" do
|
81
|
+
assert document_with_slug("some-finder/my-specialist-document", kind: "cma_case").valid?;
|
82
|
+
end
|
83
|
+
|
84
|
+
should "not allow deeper nesting" do
|
85
|
+
refute document_with_slug("some-finder/my-specialist-document/not-allowed", kind: "cma_case").valid?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
79
89
|
context "Specialist sector browse pages" do
|
80
90
|
should "allow a single path part" do
|
81
91
|
assert document_with_slug("oil-and-gas", kind: "specialist_sector").valid?
|
@@ -108,4 +118,20 @@ class SlugTest < ActiveSupport::TestCase
|
|
108
118
|
end
|
109
119
|
#TODO: disallow this once guidance migration has been complete
|
110
120
|
end
|
121
|
+
|
122
|
+
context "Manual pages" do
|
123
|
+
should "allow slugs starting guidance/" do
|
124
|
+
refute document_with_slug("manuals/a-manual", kind: "manual").valid?
|
125
|
+
assert document_with_slug("guidance/a-manual", kind: "manual").valid?
|
126
|
+
end
|
127
|
+
|
128
|
+
should "allow two or three path parts" do
|
129
|
+
refute document_with_slug("guidance", kind: "manual").valid?
|
130
|
+
assert document_with_slug("guidance/a-manual", kind: "manual").valid?
|
131
|
+
end
|
132
|
+
|
133
|
+
should "not allow invalid path segments" do
|
134
|
+
refute document_with_slug("guidance/bad.manual.slug", kind: "manual").valid?
|
135
|
+
end
|
136
|
+
end
|
111
137
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: govuk_content_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 29.1.
|
4
|
+
version: 29.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Battley
|
@@ -307,7 +307,10 @@ files:
|
|
307
307
|
- app/models/part.rb
|
308
308
|
- app/models/parted.rb
|
309
309
|
- app/models/place_edition.rb
|
310
|
+
- app/models/prerendered_entity.rb
|
310
311
|
- app/models/programme_edition.rb
|
312
|
+
- app/models/rendered_manual.rb
|
313
|
+
- app/models/rendered_specialist_document.rb
|
311
314
|
- app/models/simple_smart_answer_edition.rb
|
312
315
|
- app/models/simple_smart_answer_edition/node.rb
|
313
316
|
- app/models/simple_smart_answer_edition/node/option.rb
|
@@ -357,6 +360,7 @@ files:
|
|
357
360
|
- lib/govuk_content_models/version.rb
|
358
361
|
- lib/mongoid/monkey_patches.rb
|
359
362
|
- test/fixtures/contactotron_api_response.json
|
363
|
+
- test/fixtures/specialist_document_fixtures.rb
|
360
364
|
- test/fixtures/uploads/image.jpg
|
361
365
|
- test/models/action_test.rb
|
362
366
|
- test/models/artefact_action_test.rb
|
@@ -384,6 +388,9 @@ files:
|
|
384
388
|
- test/models/local_transaction_edition_test.rb
|
385
389
|
- test/models/overview_dashboard_test.rb
|
386
390
|
- test/models/parted_test.rb
|
391
|
+
- test/models/prerendered_entity_tests.rb
|
392
|
+
- test/models/rendered_manual_test.rb
|
393
|
+
- test/models/rendered_specialist_document_test.rb
|
387
394
|
- test/models/simple_smart_answer_edition_test.rb
|
388
395
|
- test/models/simple_smart_answer_node_test.rb
|
389
396
|
- test/models/simple_smart_answer_option_test.rb
|
@@ -429,6 +436,7 @@ specification_version: 4
|
|
429
436
|
summary: Shared models for Panopticon and Publisher, as a Rails Engine
|
430
437
|
test_files:
|
431
438
|
- test/fixtures/contactotron_api_response.json
|
439
|
+
- test/fixtures/specialist_document_fixtures.rb
|
432
440
|
- test/fixtures/uploads/image.jpg
|
433
441
|
- test/models/action_test.rb
|
434
442
|
- test/models/artefact_action_test.rb
|
@@ -456,6 +464,9 @@ test_files:
|
|
456
464
|
- test/models/local_transaction_edition_test.rb
|
457
465
|
- test/models/overview_dashboard_test.rb
|
458
466
|
- test/models/parted_test.rb
|
467
|
+
- test/models/prerendered_entity_tests.rb
|
468
|
+
- test/models/rendered_manual_test.rb
|
469
|
+
- test/models/rendered_specialist_document_test.rb
|
459
470
|
- test/models/simple_smart_answer_edition_test.rb
|
460
471
|
- test/models/simple_smart_answer_node_test.rb
|
461
472
|
- test/models/simple_smart_answer_option_test.rb
|