govuk_content_models 12.0.0 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 12.1.0
2
+
3
+ * Add LinkValidator, which checks that links in Govspeak fields are properly
4
+ formed and do not contain title text or rel=external. Remove
5
+ GovspeakSmartQuotesFixer which is irrelevant now title text is no longer
6
+ allowed.
7
+
1
8
  ## 12.0.0
2
9
 
3
10
  * Remove `SpecialistDocumentEdition` model. It is only used by the
@@ -48,6 +48,7 @@ class Edition
48
48
  validates :version_number, presence: true, uniqueness: {scope: :panopticon_id}
49
49
  validates :panopticon_id, presence: true
50
50
  validates_with SafeHtml
51
+ validates_with LinkValidator
51
52
 
52
53
  before_save :check_for_archived_artefact
53
54
  before_destroy :destroy_artefact
data/app/models/part.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require "safe_html"
2
- require 'govspeak_smart_quotes_fixer'
3
2
 
4
3
  class Part
5
4
  include Mongoid::Document
@@ -18,11 +17,10 @@ class Part
18
17
 
19
18
  GOVSPEAK_FIELDS = [:body]
20
19
 
21
- include GovspeakSmartQuotesFixer
22
-
23
20
  validates_presence_of :title
24
21
  validates_presence_of :slug
25
22
  validates_exclusion_of :slug, in: ["video"], message: "Can not be video"
26
23
  validates_format_of :slug, with: /^[a-z0-9\-]+$/i
27
24
  validates_with SafeHtml
25
+ validates_with LinkValidator
28
26
  end
@@ -2,7 +2,6 @@ require 'attachable'
2
2
  require 'parted'
3
3
  require 'state_machine'
4
4
  require 'safe_html'
5
- require 'govspeak_smart_quotes_fixer'
6
5
 
7
6
  class TravelAdviceEdition
8
7
  include Mongoid::Document
@@ -38,7 +37,6 @@ class TravelAdviceEdition
38
37
  "avoid_all_travel_to_whole_country",
39
38
  ]
40
39
 
41
- include GovspeakSmartQuotesFixer
42
40
  before_validation :populate_version_number, :on => :create
43
41
 
44
42
  validates_presence_of :country_slug, :title
@@ -47,6 +45,7 @@ class TravelAdviceEdition
47
45
  validate :alert_status_contains_valid_values
48
46
  validate :first_version_cant_be_minor_update
49
47
  validates_with SafeHtml
48
+ validates_with LinkValidator
50
49
 
51
50
  scope :published, where(:state => "published")
52
51
 
@@ -0,0 +1,48 @@
1
+ class LinkValidator < ActiveModel::Validator
2
+ def validate(record)
3
+ record.changes.each do |field_name, (_, new_value)|
4
+ if govspeak_fields(record).include?(field_name.to_sym)
5
+ messages = errors(new_value)
6
+ record.errors[field_name] << messages if messages
7
+ end
8
+ end
9
+ end
10
+
11
+ def errors(string)
12
+ link_regex = %r{
13
+ \[.*?\] # link text in literal square brackets
14
+ \( # literal opening parenthesis
15
+ (\S*?) # containing URL
16
+ (\s+"[^"]+")? # and optional space followed by title text in quotes
17
+ \) # literal close paren
18
+ (\{:rel=["']external["']\})? # optional :rel=external in literal curly brackets.
19
+ }x
20
+
21
+ errors = []
22
+
23
+ string.scan(link_regex) do |match|
24
+
25
+ error = if match[0] !~ %r{^(?:https?://|mailto:|/)}
26
+ 'Internal links must start with a forward slash eg [link text](/link-destination). External links must start with http://, https://, or mailto: eg [external link text](https://www.google.co.uk)'
27
+ elsif match[1]
28
+ %q-Don't include hover text in links. Delete the text in quotation marks eg "This appears when you hover over the link."-
29
+ elsif match[2]
30
+ 'Delete {:rel="external"} in links.'
31
+ end
32
+
33
+ errors << error if error
34
+ end
35
+ errors
36
+ end
37
+
38
+ protected
39
+
40
+ def govspeak_fields(record)
41
+ if record.class.const_defined?(:GOVSPEAK_FIELDS)
42
+ record.class.const_get(:GOVSPEAK_FIELDS)
43
+ else
44
+ []
45
+ end
46
+ end
47
+ end
48
+
@@ -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 = "12.0.0"
3
+ VERSION = "12.1.0"
4
4
  end
@@ -213,28 +213,6 @@ class TravelAdviceEditionTest < ActiveSupport::TestCase
213
213
  end
214
214
  end
215
215
 
216
- context "fixing user input" do
217
- setup do
218
- @ed = FactoryGirl.build(:travel_advice_edition)
219
- end
220
-
221
- should "convert smart quotes in the summary field" do
222
- @ed.summary = "This is a [link](https://www.gov.uk/ “link”)"
223
- @ed.save!
224
-
225
- @ed.reload
226
- assert_equal 'This is a [link](https://www.gov.uk/ "link")', @ed.summary
227
- end
228
-
229
- should "convert smart quotes in part bodies" do
230
- @ed.parts.build(:title => 'One', :slug => 'one', :body => "This is a [link](https://www.gov.uk/ “link”)")
231
- @ed.save!
232
-
233
- @ed.reload
234
- assert_equal 'This is a [link](https://www.gov.uk/ "link")', @ed.parts.first.body
235
- end
236
- end
237
-
238
216
  should "have a published scope" do
239
217
  e1 = FactoryGirl.create(:draft_travel_advice_edition)
240
218
  e2 = FactoryGirl.create(:published_travel_advice_edition)
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class LinkValidatorTest < ActiveSupport::TestCase
4
+ class Dummy
5
+ include Mongoid::Document
6
+
7
+ field "body", type: String
8
+ GOVSPEAK_FIELDS = [:body]
9
+
10
+ validates_with LinkValidator
11
+ end
12
+
13
+ context "links" do
14
+ should "start with http[s]://, mailto: or /" do
15
+ doc = Dummy.new(body: "abc [external](external.com)")
16
+ assert doc.invalid?
17
+ assert_includes doc.errors.keys, :body
18
+
19
+ doc = Dummy.new(body: "abc [external](http://external.com)")
20
+ assert doc.valid?
21
+
22
+ doc = Dummy.new(body: "abc [internal](/internal)")
23
+ assert doc.valid?
24
+ end
25
+ should "start not contain hover text" do
26
+ doc = Dummy.new(body: 'abc [foobar](foobar.com "hover")')
27
+ assert doc.invalid?
28
+ assert_includes doc.errors.keys, :body
29
+ end
30
+ should "start not set rel=external" do
31
+ doc = Dummy.new(body: 'abc [foobar](foobar.com){:rel="external"}')
32
+ assert doc.invalid?
33
+ assert_includes doc.errors.keys, :body
34
+ end
35
+ end
36
+ 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: 12.0.0
4
+ version: 12.1.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-06-09 00:00:00.000000000 Z
12
+ date: 2014-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bson_ext
@@ -389,8 +389,8 @@ files:
389
389
  - app/models/workflow.rb
390
390
  - app/models/workflow_actor.rb
391
391
  - app/traits/attachable.rb
392
- - app/traits/govspeak_smart_quotes_fixer.rb
393
392
  - app/traits/taggable.rb
393
+ - app/validators/link_validator.rb
394
394
  - app/validators/safe_html.rb
395
395
  - app/validators/slug_validator.rb
396
396
  - app/validators/tag_id_validator.rb
@@ -447,6 +447,7 @@ files:
447
447
  - test/test_helper.rb
448
448
  - test/traits/attachable_test.rb
449
449
  - test/traits/taggable_test.rb
450
+ - test/validators/link_validator_test.rb
450
451
  - test/validators/safe_html_validator_test.rb
451
452
  - test/validators/slug_validator_test.rb
452
453
  - test/validators/tag_id_validator_test.rb
@@ -465,7 +466,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
465
466
  version: '0'
466
467
  segments:
467
468
  - 0
468
- hash: 3589363428373326753
469
+ hash: 4316099945977506650
469
470
  required_rubygems_version: !ruby/object:Gem::Requirement
470
471
  none: false
471
472
  requirements:
@@ -474,7 +475,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
474
475
  version: '0'
475
476
  segments:
476
477
  - 0
477
- hash: 3589363428373326753
478
+ hash: 4316099945977506650
478
479
  requirements: []
479
480
  rubyforge_project:
480
481
  rubygems_version: 1.8.23
@@ -525,6 +526,7 @@ test_files:
525
526
  - test/test_helper.rb
526
527
  - test/traits/attachable_test.rb
527
528
  - test/traits/taggable_test.rb
529
+ - test/validators/link_validator_test.rb
528
530
  - test/validators/safe_html_validator_test.rb
529
531
  - test/validators/slug_validator_test.rb
530
532
  - test/validators/tag_id_validator_test.rb
@@ -1,19 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module GovspeakSmartQuotesFixer
4
- def self.included(model)
5
- model.class_eval do
6
- before_validation :fix_smart_quotes_in_govspeak
7
- end
8
- end
9
-
10
- private
11
-
12
- def fix_smart_quotes_in_govspeak
13
- self.class::GOVSPEAK_FIELDS.each do |field|
14
- if self.send(field) =~ /[“”]/
15
- self.send(field).gsub!(/[“”]/, '"')
16
- end
17
- end
18
- end
19
- end