govuk_content_models 6.3.0 → 6.4.0

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.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 6.4.0
2
+
3
+ Added SpecialistDocumentEdition
4
+
1
5
  ## 6.1.0
2
6
 
3
7
  makes this gem compatible with gds-sso (9.2.0)
@@ -78,6 +78,7 @@ class Artefact
78
78
  "smartanswers" => ["smart-answer"],
79
79
  "custom-application" => ["custom-application"], # In this case the owning_app is overriden. eg calendars, licencefinder
80
80
  "travel-advice-publisher" => ["travel-advice"],
81
+ "specialist-publisher" => ["specialist-document"],
81
82
  "whitehall" => ["case_study",
82
83
  "consultation",
83
84
  "detailed_guide",
@@ -0,0 +1,16 @@
1
+ class SpecialistDocumentEdition < Edition
2
+ field :summary, type: String
3
+ field :body, type: String
4
+ field :opened_date, type: Date
5
+ field :closed_date, type: Date
6
+ field :case_type, type: String
7
+ field :case_state, type: String
8
+ field :market_sector, type: String
9
+ field :outcome_type, type: String
10
+
11
+ GOVSPEAK_FIELDS = Edition::GOVSPEAK_FIELDS + [:body]
12
+
13
+ def whole_body
14
+ self.body
15
+ end
16
+ end
@@ -1,53 +1,149 @@
1
1
  class SlugValidator < ActiveModel::EachValidator
2
2
  # implement the method called during validation
3
3
  def validate_each(record, attribute, value)
4
- if value.to_s =~ /^done\/(.+)/
5
- parts = [$1]
6
- elsif value.to_s =~ /\Aforeign-travel-advice\/(.+)/ and record.kind == 'travel-advice'
7
- parts = [$1]
8
- elsif record.respond_to?(:kind) and record.kind == 'help_page'
9
- if value.to_s =~ /\Ahelp\/(.+)\z/
10
- parts = [$1]
11
- else
12
- record.errors[attribute] << "Help page slugs must have a help/ prefix"
13
- return
4
+ validators = [
5
+ DonePageValidator,
6
+ ForeignTravelAdvicePageValidator,
7
+ HelpPageValidator,
8
+ DetailedGuidePageValidator,
9
+ GovernmentPageValidator,
10
+ SpecialistDocumentPageValidator,
11
+ DefaultValidator
12
+ ].map { |klass| klass.new(record, attribute, value) }
13
+
14
+ validators.find(&:applicable?).validate!
15
+ end
16
+
17
+ protected
18
+ class InstanceValidator < Struct.new(:record, :attribute, :value)
19
+ def starts_with?(expected_prefix)
20
+ value.to_s[0...expected_prefix.size] == expected_prefix
21
+ end
22
+
23
+ def of_kind?(expected_kind)
24
+ record.respond_to?(:kind) && [*expected_kind].include?(record.kind)
25
+ end
26
+
27
+ def url_after_first_slash
28
+ value.to_s.split('/', 2)[1]
29
+ end
30
+
31
+ def url_after_first_slash_is_valid_slug!
32
+ if !valid_slug?(url_after_first_slash)
33
+ record.errors[attribute] << "must be usable in a url"
14
34
  end
15
- elsif value.to_s =~ /\Agovernment\/(.+)/ and prefixed_inside_government_format_names.include?(record.kind)
16
- parts = $1.split('/')
17
- else
18
- parts = [value.clone]
19
- end
20
-
21
- if record.respond_to?(:kind)
22
- # Inside Government formats use friendly_id to disambiguate clashes, which
23
- # potentially results in a trailing '--1' on the last path segment.
24
- # Rather than overriding the fairly robust parameterize-based validation
25
- # below, we can just fudge the friendly_id added bit
26
- if inside_government_format_names.include?(record.kind) && parts.last.include?('--')
27
- parts.last.sub!('--', '-')
35
+ end
36
+
37
+ def url_parts
38
+ value.to_s.split("/")
39
+ end
40
+
41
+ def valid_slug?(url_part)
42
+ ActiveSupport::Inflector.parameterize(url_part.to_s) == url_part.to_s
43
+ end
44
+ end
45
+
46
+ class DonePageValidator < InstanceValidator
47
+ def applicable?
48
+ starts_with?("done/")
49
+ end
50
+
51
+ def validate!
52
+ url_after_first_slash_is_valid_slug!
53
+ end
54
+ end
55
+
56
+ class ForeignTravelAdvicePageValidator < InstanceValidator
57
+ def applicable?
58
+ starts_with?("foreign-travel-advice/") && of_kind?('travel-advice')
59
+ end
60
+
61
+ def validate!
62
+ url_after_first_slash_is_valid_slug!
63
+ end
64
+ end
65
+
66
+ class HelpPageValidator < InstanceValidator
67
+ def applicable?
68
+ of_kind?('help_page')
69
+ end
70
+
71
+ def validate!
72
+ record.errors[attribute] << "Help page slugs must have a help/ prefix" unless starts_with?("help/")
73
+ url_after_first_slash_is_valid_slug!
74
+ end
75
+ end
76
+
77
+ class WhitehallFormatValidator < InstanceValidator
78
+ def url_parts
79
+ normalize_last_part_for_friendly_id(super)
80
+ end
81
+
82
+ def validate!
83
+ unless url_parts.all? { |url_part| valid_slug?(url_part) }
84
+ record.errors[attribute] << "must be usable in a URL"
28
85
  end
86
+ end
87
+
88
+ protected
29
89
 
30
- if prefixed_inside_government_format_names.include?(record.kind)
31
- unless value.to_s =~ /\Agovernment\/(.+)/
32
- record.errors[attribute] << "Inside Government slugs must have a government/ prefix"
33
- end
90
+ def normalize_last_part_for_friendly_id(url_parts)
91
+ url_parts[0...-1] + url_parts[-1..-1].map do |url_part|
92
+ normalize_for_friendly_id(url_part)
34
93
  end
35
94
  end
36
95
 
37
- parts.each do |part|
38
- unless ActiveSupport::Inflector.parameterize(part.to_s) == part.to_s
96
+ def normalize_for_friendly_id(url_part)
97
+ url_part.sub('--', '-')
98
+ end
99
+
100
+ end
101
+
102
+ class DetailedGuidePageValidator < WhitehallFormatValidator
103
+ def applicable?
104
+ of_kind?('detailed_guide')
105
+ end
106
+ end
107
+
108
+ class GovernmentPageValidator < WhitehallFormatValidator
109
+ def applicable?
110
+ record.respond_to?(:kind) && prefixed_whitehall_format_names.include?(record.kind)
111
+ end
112
+
113
+ def validate!
114
+ record.errors[attribute] << "Inside Government slugs must have a government/ prefix" unless starts_with?('government/')
115
+ super
116
+ end
117
+
118
+ protected
119
+ def prefixed_whitehall_format_names
120
+ Artefact::FORMATS_BY_DEFAULT_OWNING_APP["whitehall"] - ["detailed_guide"]
121
+ end
122
+ end
123
+
124
+ class SpecialistDocumentPageValidator < WhitehallFormatValidator
125
+ def applicable?
126
+ of_kind?('specialist-document')
127
+ end
128
+
129
+ def validate!
130
+ unless url_parts.size == 2
131
+ record.errors[attribute] << "must be of form <finder-slug>/<specialist-document-slug>"
132
+ end
133
+ unless url_parts.all? { |url_part| valid_slug?(url_part) }
39
134
  record.errors[attribute] << "must be usable in a URL"
40
135
  end
41
136
  end
42
137
  end
43
138
 
44
- private
45
- def inside_government_format_names
46
- Artefact::FORMATS_BY_DEFAULT_OWNING_APP["whitehall"]
139
+ class DefaultValidator < InstanceValidator
140
+ def applicable?
141
+ true
47
142
  end
48
143
 
49
- def prefixed_inside_government_format_names
50
- inside_government_format_names - ["detailed_guide"]
144
+ def validate!
145
+ record.errors[attribute] << "must be usable in a url" unless valid_slug?(value)
51
146
  end
147
+ end
52
148
 
53
149
  end
@@ -213,6 +213,12 @@ FactoryGirl.define do
213
213
  end
214
214
  end
215
215
 
216
+ factory :specialist_document_edition do
217
+ sequence(:slug) {|n| "test-specialist-document-#{n}" }
218
+ sequence(:title) {|n| "Test Specialist Document #{n}" }
219
+ summary "My summary"
220
+ end
221
+
216
222
  factory :simple_smart_answer_edition do
217
223
  panopticon_id {
218
224
  a = create(:artefact)
@@ -1,4 +1,4 @@
1
1
  module GovukContentModels
2
2
  # Changing this causes Jenkins to tag and release the gem into the wild
3
- VERSION = "6.3.0"
3
+ VERSION = "6.4.0"
4
4
  end
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ require "test_helper"
4
+
5
+ class SpecialistDocumentEditionTest < ActiveSupport::TestCase
6
+ should "have correct fields" do
7
+ fields = {
8
+ slug: 'cma-cases/merger-investigation-2014',
9
+ title: "Merger Investigation 2014",
10
+ summary: "This is the summary of stuff going on in the Merger Investigation 2014",
11
+ state: "published"
12
+ }
13
+
14
+ edition = SpecialistDocumentEdition.new(fields)
15
+
16
+ assert_equal fields[:title], edition.title
17
+ end
18
+
19
+ should "be persistable" do
20
+ artefact = FactoryGirl.create(:artefact)
21
+ edition = SpecialistDocumentEdition.create!(
22
+ slug: 'cma-cases/merger-investigation-2014',
23
+ title: "Merger Investigation 2014",
24
+ summary: "This is the summary of stuff going on in the Merger Investigation 2014",
25
+ state: "published",
26
+ panopticon_id: artefact.id
27
+ )
28
+
29
+ found = SpecialistDocumentEdition.where(slug: edition.slug).first
30
+ assert_equal found.attributes, edition.attributes
31
+ end
32
+ end
33
+
@@ -12,31 +12,49 @@ class SlugTest < ActiveSupport::TestCase
12
12
  validates :slug, presence: true, uniqueness: true, slug: true
13
13
  end
14
14
 
15
- context "Slugs are checked" do
16
- should "validate slugs for normal documents" do
17
- record = Dummy.new(name: "Test", slug: "test")
18
- assert record.valid?
19
- end
15
+ def document_with_slug(slug, override_options = {})
16
+ default_options = {
17
+ name: "Test",
18
+ slug: slug
19
+ }
20
+ Dummy.new(default_options.merge(override_options))
21
+ end
20
22
 
21
- should "validate help pages as starting with /help" do
22
- record = Dummy.new(name: "Help 1", slug: "test", kind: "help_page")
23
- assert record.invalid?
23
+ context "default slugs" do
24
+ should "reject url paths" do
25
+ refute document_with_slug("path/not-allowed").valid?
26
+ end
24
27
 
25
- record.slug = "help/test"
26
- assert record.valid?
28
+ should "allow a normal slug" do
29
+ assert document_with_slug("normal-slug").valid?
27
30
  end
31
+ end
28
32
 
29
- should "validate inside government slugs as containing /government" do
30
- record = Dummy.new(name: "Test 2", slug: "test", kind: "policy")
31
- assert record.invalid?
33
+ context "Help pages" do
34
+ should "must start with help/" do
35
+ refute document_with_slug("test", kind: "help_page").valid?
36
+ assert document_with_slug("help/test", kind: "help_page").valid?
37
+ end
38
+ end
32
39
 
33
- record.slug = "government/test"
34
- assert record.valid?
40
+ context "Inside government slugs" do
41
+ should "allow slug starting government/" do
42
+ refute document_with_slug("test", kind: "policy").valid?
43
+ assert document_with_slug("government/test", kind: "policy").valid?
35
44
  end
36
45
 
37
46
  should "allow friendly_id suffixes to pass" do
38
- record = Dummy.new(name: "Test 3", slug: "government/policy/test--3", kind: "policy")
39
- assert record.valid?
47
+ assert document_with_slug("government/policy/test--3", kind: "policy").valid?
48
+ end
49
+ end
50
+
51
+ context "Specialist documents" do
52
+ should "all url nested one level deep" do
53
+ assert document_with_slug("some-finder/my-specialist-document", kind: "specialist-document").valid?
54
+ end
55
+
56
+ should "not allow deeper nesting" do
57
+ refute document_with_slug("some-finder/my-specialist-document/not-allowed", kind: "specialist-document").valid?
40
58
  end
41
59
  end
42
60
  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: 6.3.0
4
+ version: 6.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-06 00:00:00.000000000 Z
12
+ date: 2014-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bson_ext
@@ -377,6 +377,7 @@ files:
377
377
  - app/models/simple_smart_answer_edition.rb
378
378
  - app/models/simple_smart_answer_edition/node.rb
379
379
  - app/models/simple_smart_answer_edition/node/option.rb
380
+ - app/models/specialist_document_edition.rb
380
381
  - app/models/tag.rb
381
382
  - app/models/transaction_edition.rb
382
383
  - app/models/travel_advice_edition.rb
@@ -426,6 +427,7 @@ files:
426
427
  - test/models/simple_smart_answer_edition_test.rb
427
428
  - test/models/simple_smart_answer_node_test.rb
428
429
  - test/models/simple_smart_answer_option_test.rb
430
+ - test/models/specialist_document_edition_test.rb
429
431
  - test/models/tag_test.rb
430
432
  - test/models/time_zone_test.rb
431
433
  - test/models/transaction_edition_test.rb
@@ -454,7 +456,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
454
456
  version: '0'
455
457
  segments:
456
458
  - 0
457
- hash: 1683068425110248072
459
+ hash: 2506025069756162727
458
460
  required_rubygems_version: !ruby/object:Gem::Requirement
459
461
  none: false
460
462
  requirements:
@@ -463,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
463
465
  version: '0'
464
466
  segments:
465
467
  - 0
466
- hash: 1683068425110248072
468
+ hash: 2506025069756162727
467
469
  requirements: []
468
470
  rubyforge_project:
469
471
  rubygems_version: 1.8.23
@@ -498,6 +500,7 @@ test_files:
498
500
  - test/models/simple_smart_answer_edition_test.rb
499
501
  - test/models/simple_smart_answer_node_test.rb
500
502
  - test/models/simple_smart_answer_option_test.rb
503
+ - test/models/specialist_document_edition_test.rb
501
504
  - test/models/tag_test.rb
502
505
  - test/models/time_zone_test.rb
503
506
  - test/models/transaction_edition_test.rb