rad_kit 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/components/captcha.rb +24 -0
- data/lib/components/captcha.yml +2 -0
- data/lib/kit/{http_controller → controller}/authorized.rb +1 -1
- data/lib/kit/controller/captcha.rb +23 -0
- data/lib/kit/{http_controller → controller}/localized.rb +1 -1
- data/lib/kit/controller.rb +5 -0
- data/lib/kit/gems.rb +10 -6
- data/lib/kit/i18n/locales/ru/pluralization.rb +62 -0
- data/lib/kit/i18n.rb +16 -0
- data/lib/kit/kit.rb +10 -7
- data/lib/kit/kit_text_utils.rb +30 -0
- data/lib/kit/misc/prepare_model.rb +16 -0
- data/lib/kit/misc/user_error.rb +12 -0
- data/lib/kit/models/attachments_uploader_helper.rb +1 -1
- data/lib/kit/models/authorized.rb +6 -8
- data/lib/kit/models/authorized_object.rb +3 -4
- data/lib/kit/models/{micelaneous.rb → miscellaneous.rb} +0 -0
- data/lib/kit/models_after.rb +1 -1
- data/lib/kit/mongoid/{rad_micelaneous.rb → rad_miscellaneous.rb} +1 -1
- data/lib/kit/mongoid/text_processor.rb +1 -1
- data/lib/kit/mongoid.rb +2 -2
- data/lib/kit/spec.rb +1 -2
- data/lib/kit/tasks.rb +1 -1
- data/lib/text_utils/code_highlighter.rb +75 -0
- data/lib/text_utils/custom_markdown.rb +64 -0
- data/lib/text_utils/ensure_utf.rb +14 -0
- data/lib/text_utils/format_qualifier.rb +13 -0
- data/lib/{kit/text_utils → text_utils}/html_sanitizer.rb +8 -6
- data/lib/text_utils/markdown.rb +33 -0
- data/lib/text_utils/pipe.rb +16 -0
- data/lib/text_utils/processor.rb +14 -0
- data/lib/text_utils/support.rb +15 -0
- data/lib/text_utils/truncate.rb +30 -0
- data/lib/text_utils.rb +23 -0
- data/readme.md +1 -8
- data/spec/controller/authorization_spec.rb +1 -1
- data/spec/controller/captcha_spec.rb +66 -0
- data/spec/i18n/i18n_spec/locales/en/general.yml +5 -0
- data/spec/i18n/i18n_spec/locales/ru/general.yml +7 -0
- data/spec/i18n/i18n_spec.rb +32 -0
- data/spec/misc/kit_text_utils_spec.rb +29 -0
- data/spec/misc/prepare_model_spec.rb +37 -0
- data/spec/misc/user_error_spec.rb +38 -0
- data/spec/models/authorized_object_spec.rb +10 -3
- data/spec/spec_helper/factories.rb +4 -0
- data/spec/spec_helper/user.rb +2 -3
- data/spec/spec_helper.rb +0 -5
- data/spec/text_utils/code_highlighter_spec.rb +38 -0
- data/spec/text_utils/custom_markdown_spec.rb +82 -0
- data/spec/text_utils/format_qualifier_spec.rb +37 -0
- data/spec/text_utils/html_sanitizer_spec.rb +88 -0
- data/spec/text_utils/markdown_spec.rb +114 -0
- data/spec/text_utils/pipe_spec.rb +35 -0
- data/spec/text_utils/spec_helper.rb +26 -0
- data/spec/text_utils/text_processor_shared.rb +9 -0
- data/spec/text_utils/truncate_spec.rb +22 -0
- metadata +57 -47
- data/lib/kit/http_controller.rb +0 -4
- data/lib/kit/text_utils/code_highlighter.rb +0 -58
- data/lib/kit/text_utils/custom_markdown.rb +0 -90
- data/lib/kit/text_utils/ensure_utf.rb +0 -8
- data/lib/kit/text_utils/github_flavoured_markdown.rb +0 -32
- data/lib/kit/text_utils/image_box.rb +0 -35
- data/lib/kit/text_utils/markup.rb +0 -43
- data/lib/kit/text_utils/processor.rb +0 -25
- data/lib/kit/text_utils/tag_shortcuts.rb +0 -14
- data/lib/kit/text_utils/truncate.rb +0 -29
- data/lib/kit/text_utils/truncator.rb +0 -15
- data/lib/kit/text_utils/urls.rb +0 -13
- data/lib/kit/text_utils.rb +0 -43
- data/spec/utils/text_utils_spec.rb +0 -280
@@ -0,0 +1,16 @@
|
|
1
|
+
class TextUtils::Pipe
|
2
|
+
def initialize *processors
|
3
|
+
@processor = processors.reverse.inject nil do |next_processor, meta|
|
4
|
+
klass, args = if meta.is_a? Array
|
5
|
+
[meta[0], meta[1..-1]]
|
6
|
+
else
|
7
|
+
[meta, []]
|
8
|
+
end
|
9
|
+
klass.new next_processor, *args
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def call text
|
14
|
+
@processor.call text, {}
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Object.class_eval do
|
2
|
+
unless method_defined? :try
|
3
|
+
def try method
|
4
|
+
self && self.send(method)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
class String
|
11
|
+
def self.random length = 3
|
12
|
+
@digits ||= ('a'..'z').to_a + (0..9).to_a
|
13
|
+
(0..(length-1)).map{@digits[rand(@digits.size)]}.join
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class TextUtils::Truncate < TextUtils::Processor
|
2
|
+
def initialize processor, length
|
3
|
+
super processor
|
4
|
+
@length = length
|
5
|
+
end
|
6
|
+
|
7
|
+
def call data, env
|
8
|
+
data ||= ""
|
9
|
+
|
10
|
+
# strip from HTML tags
|
11
|
+
data = data.gsub("<br", " <br").gsub("<p", " <p") # to preserve space in place of <> html elements
|
12
|
+
doc = Nokogiri::XML("<div class='root'>#{data}</div>")
|
13
|
+
data = doc.css('.root').first.content
|
14
|
+
|
15
|
+
# remove clear space
|
16
|
+
data = data.gsub(/\s+/, ' ')
|
17
|
+
|
18
|
+
# truncate with no broken words
|
19
|
+
data = if data.length >= @length
|
20
|
+
shortened = data[0, @length]
|
21
|
+
splitted = shortened.split(/\s/)
|
22
|
+
words = splitted.length
|
23
|
+
splitted[0, words-1].join(" ") + ' ...'
|
24
|
+
else
|
25
|
+
data
|
26
|
+
end
|
27
|
+
|
28
|
+
call_next data, env
|
29
|
+
end
|
30
|
+
end
|
data/lib/text_utils.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'iconv'
|
3
|
+
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'bluecloth'
|
6
|
+
require 'sanitize'
|
7
|
+
|
8
|
+
module TextUtils; end
|
9
|
+
|
10
|
+
%w(
|
11
|
+
support
|
12
|
+
|
13
|
+
processor
|
14
|
+
|
15
|
+
ensure_utf
|
16
|
+
html_sanitizer
|
17
|
+
format_qualifier
|
18
|
+
truncate
|
19
|
+
markdown
|
20
|
+
custom_markdown
|
21
|
+
pipe
|
22
|
+
code_highlighter
|
23
|
+
).each{|f| require "text_utils/#{f}"}
|
data/readme.md
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Captcha" do
|
4
|
+
before :all do
|
5
|
+
class TheController
|
6
|
+
inherit Rad::Controller::Http, Rad::Controller::Captcha
|
7
|
+
|
8
|
+
def action
|
9
|
+
render inline: 'ok'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
after(:all){remove_constants :TheController}
|
14
|
+
|
15
|
+
before do
|
16
|
+
rad.captcha.stub!(:enabled).and_return(true)
|
17
|
+
|
18
|
+
@request = Rad::Http::Request.stub
|
19
|
+
@request.stub!(:from_browser?).and_return(true)
|
20
|
+
|
21
|
+
@params = Rad::Conveyors::Params.new
|
22
|
+
|
23
|
+
@controller = TheController.new
|
24
|
+
@controller.stub!(:request).and_return(@request)
|
25
|
+
@controller.stub!(:params).and_return(@params)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should allow get for anyone" do
|
29
|
+
@request.stub!(:get?).and_return(true)
|
30
|
+
|
31
|
+
rad.user = Factory.build :anonymous
|
32
|
+
@controller.call(:action).should == 'ok'
|
33
|
+
|
34
|
+
rad.user = Factory.build :registered
|
35
|
+
@controller.call(:action).should == 'ok'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "shouldn't allow non-get for anonymous" do
|
39
|
+
@request.stub!(:get?).and_return(false)
|
40
|
+
|
41
|
+
rad.user = Factory.build :anonymous
|
42
|
+
-> {@controller.call(:action)}.should raise_error(UserError)
|
43
|
+
|
44
|
+
rad.user = Factory.build :registered
|
45
|
+
@controller.call(:action).should == 'ok'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should display captcha form for anonymous if format is :js" do
|
49
|
+
@request.stub!(:get?).and_return(false)
|
50
|
+
@params.format = 'js'
|
51
|
+
rad.captcha.stub!(:verify).and_return(false)
|
52
|
+
rad.user = Factory.build :anonymous
|
53
|
+
@controller.stub!(:render).and_return('form')
|
54
|
+
|
55
|
+
@controller.call(:action).should == 'form'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow anonymous access if it solved captcha" do
|
59
|
+
@request.stub!(:get?).and_return(false)
|
60
|
+
@params.format = 'js'
|
61
|
+
rad.captcha.stub!(:verify).and_return(true)
|
62
|
+
rad.user = Factory.build :anonymous
|
63
|
+
|
64
|
+
@controller.call(:action).should == 'ok'
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe 'I18n' do
|
6
|
+
before :all do
|
7
|
+
rad.web
|
8
|
+
rad.reset :conveyors
|
9
|
+
|
10
|
+
I18n.load_path += Dir["#{spec_dir}/locales/*/*.{rb,yml}"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def t *args
|
14
|
+
I18n.t *args
|
15
|
+
end
|
16
|
+
|
17
|
+
it "basic" do
|
18
|
+
I18n.locale = 'en'
|
19
|
+
t(:name).should == "Name"
|
20
|
+
t(:name).is_a?(String).should be_true
|
21
|
+
|
22
|
+
I18n.locale = 'ru'
|
23
|
+
t(:name).should == "Имя"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "pluggable pluralization" do
|
27
|
+
I18n.locale = 'ru'
|
28
|
+
t(:comments_count, count: 1).should == "1 комментарий"
|
29
|
+
t(:comments_count, count: 2).should == "2 комментария"
|
30
|
+
t(:comments_count, count: 5).should == "5 комментариев"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "TextUtils with Kit extensions" do
|
4
|
+
it "should truncate" do
|
5
|
+
TextUtils.truncate('lorem ipsum', 10).should == 'lorem ...'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should process markdown (should qualify markdown format automatically)" do
|
9
|
+
TextUtils.markup('lorem **ipsum**').should == '<p>lorem <strong>ipsum</strong></p>'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should process html (should qualify html format automatically)" do
|
13
|
+
TextUtils.markup('<p>lorem **ipsum**</p>').should == '<p>lorem **ipsum**</p>'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "code highlight" do
|
17
|
+
rad.config.stub!(:use_code_highlighter).and_return(true)
|
18
|
+
|
19
|
+
markdown = <<MARKDOWN
|
20
|
+
code
|
21
|
+
|
22
|
+
``` ruby
|
23
|
+
puts "Hello World"
|
24
|
+
```
|
25
|
+
MARKDOWN
|
26
|
+
|
27
|
+
TextUtils.markup(markdown).should =~ /span/i
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "User Error" do
|
4
|
+
isolate :conveyors, :router, before: :all
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
rad.delete :conveyors
|
8
|
+
rad.conveyors.web do |web|
|
9
|
+
web.use Rad::Controller::Processors::ControllerCaller
|
10
|
+
end
|
11
|
+
|
12
|
+
class ::SomeModel
|
13
|
+
def self.find! id
|
14
|
+
id.should == 'some id'
|
15
|
+
SomeModel.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
after :all do
|
20
|
+
remove_constants %w(SomeModel ControllerSpec)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "user error" do
|
24
|
+
class ::ControllerSpec
|
25
|
+
inherit Rad::Controller::Http
|
26
|
+
|
27
|
+
prepare_model SomeModel, id: :some_model, variable: 'some_model'
|
28
|
+
|
29
|
+
def action
|
30
|
+
@some_model.should_not == nil
|
31
|
+
render inline: 'ok'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ccall(ControllerSpec, :action, some_model: 'some id').should == 'ok'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "User Error" do
|
4
|
+
isolate :conveyors, :router, before: :all
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
rad.delete :conveyors
|
8
|
+
rad.conveyors.web do |web|
|
9
|
+
web.use Rad::Controller::Processors::ControllerCaller
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
remove_constants %w(UserErrorSpec)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "user error" do
|
18
|
+
class ::UserErrorSpec
|
19
|
+
inherit Rad::Controller::Http
|
20
|
+
|
21
|
+
def action
|
22
|
+
raise_user_error "some error"
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
def catch_user_error
|
27
|
+
begin
|
28
|
+
yield
|
29
|
+
rescue UserError => ue
|
30
|
+
render inline: "Catched #{ue.message}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
around :catch_user_error
|
34
|
+
end
|
35
|
+
|
36
|
+
ccall(UserErrorSpec, :action).should == "Catched some error"
|
37
|
+
end
|
38
|
+
end
|
@@ -98,6 +98,13 @@ describe "Authorized Object" do
|
|
98
98
|
o.normalized_collaborators.should == %w{manager member user:auser}
|
99
99
|
end
|
100
100
|
|
101
|
+
it "anonymous should never be collaborator (from error)" do
|
102
|
+
@user = Factory.build :anonymous
|
103
|
+
o = AModel.new
|
104
|
+
o.owner = @user
|
105
|
+
o.normalized_collaborators.should == []
|
106
|
+
end
|
107
|
+
|
101
108
|
it "viewers and collaborators dependance" do
|
102
109
|
o = AModel.new
|
103
110
|
o.owner = @user
|
@@ -174,8 +181,8 @@ describe "Authorized Object" do
|
|
174
181
|
@object = AModel.new
|
175
182
|
@owned_object = AModel.new
|
176
183
|
@owned_object.owner = @user
|
177
|
-
end
|
178
|
-
|
184
|
+
end
|
185
|
+
|
179
186
|
it "owner?" do
|
180
187
|
@user.should_not be_owner(@object)
|
181
188
|
@user.should be_owner(@owned_object)
|
@@ -189,7 +196,7 @@ describe "Authorized Object" do
|
|
189
196
|
|
190
197
|
@user.should_not be_owner(@owned_object)
|
191
198
|
end
|
192
|
-
|
199
|
+
|
193
200
|
it 'permissions for owner' do
|
194
201
|
@user.can?(:manage, @object).should be_false
|
195
202
|
@user.can?(:manage, @owned_object).should be_true
|
data/spec/spec_helper/user.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "Markdown" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@processor = TextUtils::CodeHighlighter.new
|
8
|
+
@options = {format: :html}
|
9
|
+
end
|
10
|
+
|
11
|
+
it_should_behave_like 'text processor'
|
12
|
+
|
13
|
+
it "basic" do
|
14
|
+
process(%{<p> text </p><code lang='ruby'>class A; p "Hello World" end</code><p> text </p>}).should =~ /span/i
|
15
|
+
process(%{<p> text </p><code language='ruby'>class A; p "Hello World" end</code><p> text </p>}).should =~ /span/i
|
16
|
+
process(%{<code lang='ruby'>\nclass A \n def p\n 10\n end\nend \n</code>}).should =~ /span/i
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should works with < and > in code" do
|
20
|
+
process(%{<code lang='ruby'>class A < ClassB; end</code>}).should include('ClassB')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should preserve custom classes in <code>' do
|
24
|
+
process(%{<code lang='ruby' class='my_code'>\nclass A \n def p\n 10\n end\nend \n</code>}).should =~ /my_code/i
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'markdown' do
|
28
|
+
markdown = <<MARKDOWN
|
29
|
+
text
|
30
|
+
|
31
|
+
``` ruby
|
32
|
+
print "Hello World"
|
33
|
+
```
|
34
|
+
MARKDOWN
|
35
|
+
|
36
|
+
process(markdown).should =~ /span/i
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "Markdown" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
markdown = TextUtils::Markdown.new
|
8
|
+
@processor = TextUtils::CustomMarkdown.new markdown
|
9
|
+
@options = {format: :markdown}
|
10
|
+
end
|
11
|
+
|
12
|
+
it_should_behave_like 'text processor'
|
13
|
+
|
14
|
+
it "should apply markup inside of html elements (from error)" do
|
15
|
+
html = <<HTML
|
16
|
+
<div class='right'>
|
17
|
+
![img]
|
18
|
+
</div>
|
19
|
+
|
20
|
+
[img]: /some_link
|
21
|
+
HTML
|
22
|
+
|
23
|
+
to_doc(html).css('.right img').size.should == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should leave existing links intact" do
|
27
|
+
doc = to_doc(%{<a href="http://some_domain.com">http://some_domain.com</a>})
|
28
|
+
doc.css('a').size.should == 1
|
29
|
+
doc.css('a').first['href'].should == "http://some_domain.com"
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'image box' do
|
33
|
+
it "should use simplifyed syntax for image boxes (!![img_thumb] => [![img_thumb]][img_full_version])" do
|
34
|
+
html = <<HTML
|
35
|
+
!![img]
|
36
|
+
![img]
|
37
|
+
|
38
|
+
!![img_2]
|
39
|
+
![img_2]
|
40
|
+
|
41
|
+
[img]: /some_prefix/image_name.png
|
42
|
+
[img_2]: /some_prefix/image_name2.icon.png
|
43
|
+
HTML
|
44
|
+
|
45
|
+
doc = to_doc html
|
46
|
+
doc.css('a').first.to_fuzzy_hash.should == {href: "/some_prefix/image_name.png"}
|
47
|
+
doc.css('a img').first.to_fuzzy_hash.should == {src: "/some_prefix/image_name.thumb.png"}
|
48
|
+
|
49
|
+
doc.css('a').last.to_fuzzy_hash.should == {href: "/some_prefix/image_name2.png"}
|
50
|
+
doc.css('a img').last.to_fuzzy_hash.should == {src: "/some_prefix/image_name2.icon.png"}
|
51
|
+
|
52
|
+
doc.css('img').size.should == 4
|
53
|
+
end
|
54
|
+
|
55
|
+
it "simplifyed syntax for image boxes should be robust (from error)" do
|
56
|
+
html = "!![img] " # without resolved reference
|
57
|
+
lambda{process(html)}.should_not raise_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# discarded
|
62
|
+
# it "clear div" do
|
63
|
+
# html = "[clear]"
|
64
|
+
#
|
65
|
+
# doc = to_doc html
|
66
|
+
# doc.css('div.clear').size.should == 1
|
67
|
+
# end
|
68
|
+
|
69
|
+
# discarded
|
70
|
+
# it "space div" do
|
71
|
+
# html = "[space]"
|
72
|
+
#
|
73
|
+
# doc = to_doc html
|
74
|
+
# doc.css('div.space').size.should == 1
|
75
|
+
# end
|
76
|
+
|
77
|
+
# discarded
|
78
|
+
# it "should skip empty paragraphs" do
|
79
|
+
# html = "line 1\n\nline 2\n\n\n\nline 3"
|
80
|
+
# process(html).should =~ /<p>\s*line 1<\/p>\n<p>line 2<\/p>\n<p>line 3\s*<\/p>.?/
|
81
|
+
# end
|
82
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "FormatQualifier" do
|
4
|
+
before do
|
5
|
+
@processor = TextUtils::FormatQualifier.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it_should_behave_like 'text processor'
|
9
|
+
|
10
|
+
it "should qualify format" do
|
11
|
+
[
|
12
|
+
'<b>some</b>', :html,
|
13
|
+
'<b>some</b> <p>other</p>', :html,
|
14
|
+
' <b> some</b> ', :html,
|
15
|
+
'<b/>', :html,
|
16
|
+
'<b>', :markdown,
|
17
|
+
'abc', :markdown
|
18
|
+
].each_slice 2 do |text, format|
|
19
|
+
env = {}
|
20
|
+
@processor.call(text, env)
|
21
|
+
env[:format].should == format
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should qualify :html (from error)" do
|
26
|
+
html = <<HTML
|
27
|
+
<h2>Title</h2>
|
28
|
+
|
29
|
+
<p>body</p>
|
30
|
+
HTML
|
31
|
+
|
32
|
+
env = {}
|
33
|
+
@processor.call(html, env)
|
34
|
+
env[:format].should == :html
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "HtmlSanitizer" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@processor = TextUtils::HtmlSanitizer.new
|
8
|
+
@options = {format: :html}
|
9
|
+
end
|
10
|
+
|
11
|
+
it_should_behave_like 'text processor'
|
12
|
+
|
13
|
+
it "should escape restricted tags" do
|
14
|
+
%w(script object).each do |tag|
|
15
|
+
html = "<#{tag}}>some text</#{tag}>"
|
16
|
+
process(html).should_not include(tag)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "shouldn't escape non-restricted tags" do
|
21
|
+
common_attr_names = %w(class style)
|
22
|
+
{
|
23
|
+
iframe: %w(height scrolling src width),
|
24
|
+
a: %w(href title rel)
|
25
|
+
}.each do |tag, attr_names|
|
26
|
+
attrs = {}; (common_attr_names + attr_names).each{|n| attrs[n] = 'value'}
|
27
|
+
|
28
|
+
attrs_html = ""; attrs.each{|n, v| attrs_html << "#{n}='#{v}'"}
|
29
|
+
html = "<#{tag} #{attrs_html}}>some text</#{tag}>"
|
30
|
+
|
31
|
+
to_doc(html).css(tag.to_s).first.to_fuzzy_hash.should == attrs
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow image inside of link (from error)" do
|
36
|
+
html = <<HTML
|
37
|
+
<a rel="images" class="image_box" href="/some_image">
|
38
|
+
<img src="/some_image"/>
|
39
|
+
</a>
|
40
|
+
HTML
|
41
|
+
|
42
|
+
doc = to_doc html
|
43
|
+
doc.css('a').first.to_fuzzy_hash.should == {href: "/some_image", class: "image_box"}
|
44
|
+
doc.css('a img').first.to_fuzzy_hash.should == {src: "/some_image"}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should allow 'a' elements (from error)" do
|
48
|
+
html = <<HTML
|
49
|
+
<a href="http://www.some.com/some">Absolute Link</a>
|
50
|
+
<a href="/some">Relative Link</a>
|
51
|
+
HTML
|
52
|
+
|
53
|
+
doc = to_doc html
|
54
|
+
doc.css("a").first[:href].should == "http://www.some.com/some"
|
55
|
+
doc.css("a").last[:href].should == "/some"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow div with any classes (from error)" do
|
59
|
+
html = %{<div class="col3 left"><a href='#'>text</a></div>}
|
60
|
+
to_doc(html).css("div.col3.left a").size.should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should embed YouTube Videos" do
|
64
|
+
html =<<HTML
|
65
|
+
<object width="425" height="344">
|
66
|
+
<param name="movie" value="http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&"></param>
|
67
|
+
<param name="allowFullScreen" value="true"></param>
|
68
|
+
<param name="allowscriptaccess" value="always"></param>
|
69
|
+
<embed src="http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
|
70
|
+
</object>
|
71
|
+
HTML
|
72
|
+
|
73
|
+
doc = to_doc html
|
74
|
+
obj = doc.css("object").first.to_fuzzy_hash.should == {width: '425', height: '344'}
|
75
|
+
p1, p2, p3, embed = doc.css('object *')
|
76
|
+
p1.to_fuzzy_hash.should == {name: 'movie', value: 'http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&'}
|
77
|
+
p2.to_fuzzy_hash.should == {name: 'allowFullScreen', value: 'true'}
|
78
|
+
p3.to_fuzzy_hash.should == {name: 'allowscriptaccess', value: 'always'}
|
79
|
+
embed.to_fuzzy_hash.should == {
|
80
|
+
src: 'http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&',
|
81
|
+
type: 'application/x-shockwave-flash',
|
82
|
+
allowscriptaccess: 'always',
|
83
|
+
allowfullscreen: 'true',
|
84
|
+
width: '425',
|
85
|
+
height: '344'
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|