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 +7 -0
- data/app/models/edition.rb +1 -0
- data/app/models/part.rb +1 -3
- data/app/models/travel_advice_edition.rb +1 -2
- data/app/validators/link_validator.rb +48 -0
- data/lib/govuk_content_models/version.rb +1 -1
- data/test/models/travel_advice_edition_test.rb +0 -22
- data/test/validators/link_validator_test.rb +36 -0
- metadata +7 -5
- data/app/traits/govspeak_smart_quotes_fixer.rb +0 -19
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
|
data/app/models/edition.rb
CHANGED
@@ -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
|
+
|
@@ -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.
|
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-
|
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:
|
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:
|
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
|