typo 4.0.0 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/admin/comments_controller.rb +1 -1
- data/app/controllers/admin/content_controller.rb +1 -3
- data/app/controllers/admin/feedback_controller.rb +36 -31
- data/app/controllers/admin/sidebar_controller.rb +13 -2
- data/app/controllers/admin/users_controller.rb +2 -1
- data/app/controllers/articles_controller.rb +10 -19
- data/app/controllers/xml_controller.rb +2 -2
- data/app/helpers/admin/base_helper.rb +7 -3
- data/app/helpers/application_helper.rb +2 -2
- data/app/helpers/articles_helper.rb +5 -4
- data/app/models/article.rb +16 -10
- data/app/models/blog.rb +4 -10
- data/app/models/comment.rb +17 -36
- data/app/models/content.rb +31 -53
- data/app/models/content_state/base.rb +46 -3
- data/app/models/content_state/draft.rb +2 -9
- data/app/models/content_state/ham.rb +31 -0
- data/app/models/content_state/just_marked_as_ham.rb +10 -0
- data/app/models/content_state/just_marked_as_spam.rb +23 -0
- data/app/models/content_state/just_presumed_ham.rb +37 -0
- data/app/models/content_state/just_published.rb +15 -8
- data/app/models/content_state/new.rb +3 -10
- data/app/models/content_state/presumed_ham.rb +27 -0
- data/app/models/content_state/presumed_spam.rb +31 -0
- data/app/models/content_state/publication_pending.rb +7 -9
- data/app/models/content_state/published.rb +10 -9
- data/app/models/content_state/spam.rb +23 -0
- data/app/models/content_state/unclassified.rb +29 -0
- data/app/models/content_state/withdrawn.rb +28 -0
- data/app/models/email_notifier.rb +0 -1
- data/app/models/feedback.rb +151 -0
- data/app/models/trackback.rb +22 -29
- data/app/views/admin/feedback/_item.rhtml +5 -5
- data/app/views/admin/feedback/list.rhtml +13 -11
- data/app/views/admin/general/index.rhtml +8 -4
- data/app/views/admin/users/show.rhtml +7 -1
- data/app/views/articles/read.rhtml +2 -2
- data/bin/typo +7 -6
- data/components/plugins/sidebars/recent_comments_controller.rb +1 -1
- data/config/environment.rb +2 -0
- data/db/migrate/046_fixup_forthcoming_publications.rb +1 -1
- data/db/migrate/048_remove_count_caching.rb +31 -0
- data/db/migrate/049_move_feedback_to_new_state_machine.rb +33 -0
- data/db/schema.mysql-v3.sql +3 -4
- data/db/schema.mysql.sql +3 -4
- data/db/schema.postgresql.sql +3 -4
- data/db/schema.rb +12 -17
- data/db/schema.sqlite.sql +3 -4
- data/db/schema.sqlserver.sql +3 -4
- data/db/schema_version +1 -1
- data/doc/Installer.txt +4 -0
- data/lib/jabber_notify.rb +6 -2
- data/lib/sidebars/plugin.rb +2 -1
- data/lib/tasks/release.rake +5 -4
- data/lib/typo_version.rb +1 -1
- data/public/stylesheets/administration.css +22 -2
- data/test/fixtures/blogs.yml +2 -0
- data/test/fixtures/contents.yml +7 -7
- data/test/functional/admin/users_controller_test.rb +3 -0
- data/test/functional/articles_controller_test.rb +16 -1
- data/test/mocks/test/xmlrpc_mock.rb +5 -4
- data/test/unit/article_test.rb +16 -4
- data/test/unit/comment_test.rb +57 -35
- data/test/unit/content_state/factory_test.rb +7 -6
- data/test/unit/ping_test.rb +14 -0
- data/test/unit/trackback_test.rb +16 -15
- metadata +26 -26
- data/config/database.yml-pgsql +0 -17
- data/config/database.yml.sqlite +0 -14
- data/config/mail.yml +0 -8
- data/config/mongrel.conf +0 -2
- data/db/converters/mt-import.rb +0 -72
- data/db/development_structure.sql +0 -691
- data/installer/rails-installer.rb +0 -527
- data/installer/rails-installer/commands.rb +0 -118
- data/installer/rails-installer/web-servers.rb +0 -110
- data/log/development.log-1 +0 -991
- data/log/development.log-2 +0 -422
- data/log/development.log-3 +0 -429
- data/log/development.log-4 +0 -174
- data/svk-commitP6cVv.tmp +0 -1
- data/vendor/ruby-mp3info/lib/mp3info.rb +0 -720
data/lib/typo_version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
TYPO_VERSION = '4.0.
|
1
|
+
TYPO_VERSION = '4.0.1'
|
@@ -81,9 +81,8 @@
|
|
81
81
|
|
82
82
|
#tabs-container {
|
83
83
|
height: 20px;
|
84
|
-
width:
|
84
|
+
width: auto;
|
85
85
|
padding: 14px 0 0 100px;
|
86
|
-
height: 16px;
|
87
86
|
margin-top: -40px;
|
88
87
|
border-bottom: 1px solid #637987;
|
89
88
|
background: #F8F7EF;
|
@@ -628,3 +627,24 @@ div.user {
|
|
628
627
|
.feedbackbody td {
|
629
628
|
border-bottom: 1px dotted #ccc;
|
630
629
|
}
|
630
|
+
|
631
|
+
.presumed_ham td {
|
632
|
+
border-bottom: 1px dotted #ccc;
|
633
|
+
}
|
634
|
+
|
635
|
+
.presumed_spam td {
|
636
|
+
border-bottom: 1px dotted #ccc;
|
637
|
+
}
|
638
|
+
|
639
|
+
.ham td {
|
640
|
+
border-bottom: 1px dotted #ccc;
|
641
|
+
}
|
642
|
+
|
643
|
+
.spam td {
|
644
|
+
border-bottom: 1px dotted #ccc;
|
645
|
+
}
|
646
|
+
|
647
|
+
.spam .state {
|
648
|
+
font-weight: bold
|
649
|
+
}
|
650
|
+
|
data/test/fixtures/blogs.yml
CHANGED
@@ -6,6 +6,7 @@ default:
|
|
6
6
|
show_extended_on_rss: true
|
7
7
|
itunes_owner: ""
|
8
8
|
blog_name: test blog
|
9
|
+
title_prefix: true
|
9
10
|
limit_article_display: 10
|
10
11
|
sp_url_limit: 3
|
11
12
|
use_gravatar: false
|
@@ -43,6 +44,7 @@ second:
|
|
43
44
|
show_extended_on_rss: true
|
44
45
|
itunes_owner: ""
|
45
46
|
blog_name: second test blog
|
47
|
+
title_prefix: false
|
46
48
|
limit_article_display: 10
|
47
49
|
sp_url_limit: 0
|
48
50
|
use_gravatar: false
|
data/test/fixtures/contents.yml
CHANGED
@@ -96,7 +96,7 @@ spam_comment:
|
|
96
96
|
updated_at: 2005-01-01 02:00:00
|
97
97
|
published_at: 2005-01-01 02:00:00
|
98
98
|
guid: 12313123123123123
|
99
|
-
state: ContentState::
|
99
|
+
state: ContentState::Ham
|
100
100
|
|
101
101
|
comment2:
|
102
102
|
type: Comment
|
@@ -113,14 +113,14 @@ comment2:
|
|
113
113
|
updated_at: 2005-01-01 02:00:01
|
114
114
|
published_at: 2005-01-01 02:00:01
|
115
115
|
guid: 453456456456456
|
116
|
-
state: ContentState::
|
116
|
+
state: ContentState::Ham
|
117
117
|
|
118
118
|
comment3:
|
119
119
|
type: Comment
|
120
120
|
blog_id: 1
|
121
121
|
id: 12
|
122
122
|
published: false
|
123
|
-
state: ContentState::
|
123
|
+
state: ContentState::PresumedSpam
|
124
124
|
article_id: 1
|
125
125
|
author: Foo Bar
|
126
126
|
body: Zzzzzz
|
@@ -135,7 +135,7 @@ trackback1:
|
|
135
135
|
id: 7
|
136
136
|
article_id: 2
|
137
137
|
published: false
|
138
|
-
state: ContentState::
|
138
|
+
state: ContentState::PresumedSpam
|
139
139
|
blog_name: Trackback Blog
|
140
140
|
title: Trackback Entry
|
141
141
|
url: http://www.example.com
|
@@ -150,7 +150,7 @@ trackback2:
|
|
150
150
|
blog_id: 1
|
151
151
|
id: 8
|
152
152
|
article_id: 1
|
153
|
-
state: ContentState::
|
153
|
+
state: ContentState::PresumedHam
|
154
154
|
published: true
|
155
155
|
blog_name: Trackback Blog
|
156
156
|
title: Trackback Entry
|
@@ -167,7 +167,7 @@ trackback3:
|
|
167
167
|
id: 13
|
168
168
|
article_id: 1
|
169
169
|
published: true
|
170
|
-
state: ContentState::
|
170
|
+
state: ContentState::PresumedHam
|
171
171
|
blog_name: Trackback Blog 2
|
172
172
|
title: Trackback Entry 2
|
173
173
|
url: http://www.example.com
|
@@ -255,7 +255,7 @@ old_comment:
|
|
255
255
|
updated_at: 2004-05-02 20:00:02
|
256
256
|
published_at: 2004-05-02 20:00:02
|
257
257
|
published: true
|
258
|
-
state: ContentState::
|
258
|
+
state: ContentState::Ham
|
259
259
|
|
260
260
|
second_blog_article:
|
261
261
|
type: Article
|
@@ -107,6 +107,19 @@ class ArticlesControllerTest < Test::Unit::TestCase
|
|
107
107
|
assert_response :success
|
108
108
|
assert_rendered_file "archives"
|
109
109
|
end
|
110
|
+
|
111
|
+
def test_blog_title
|
112
|
+
blogs(:default).title_prefix = true
|
113
|
+
get :permalink, :year => 2004, :month => 06, :day => 01, :title => "article-3"
|
114
|
+
assert_response :success
|
115
|
+
assert_tag :tag => 'title', :content => /^test blog : Article 3!$/
|
116
|
+
|
117
|
+
blogs(:default).title_prefix = false
|
118
|
+
get :permalink, :year => 2004, :month => 06, :day => 01, :title => "article-3"
|
119
|
+
assert_response :success
|
120
|
+
assert_tag :tag => 'title', :content => /^Article 3!$/
|
121
|
+
|
122
|
+
end
|
110
123
|
|
111
124
|
# Permalinks
|
112
125
|
def test_permalink
|
@@ -116,7 +129,7 @@ class ArticlesControllerTest < Test::Unit::TestCase
|
|
116
129
|
assert_not_nil assigns(:article)
|
117
130
|
assert_equal contents(:article3), assigns(:article)
|
118
131
|
end
|
119
|
-
|
132
|
+
|
120
133
|
# Posts for given day
|
121
134
|
def test_find_by_date
|
122
135
|
get :find_by_date, :year => 2004, :month => 06, :day => 01
|
@@ -354,6 +367,8 @@ class ArticlesControllerTest < Test::Unit::TestCase
|
|
354
367
|
get :read, :id => contents(:article1).id
|
355
368
|
assert_response :success
|
356
369
|
assert_template "read"
|
370
|
+
|
371
|
+
assert_equal contents(:article1).comments.to_a.select{|c| c.published?}, contents(:article1).published_comments
|
357
372
|
|
358
373
|
assert_tag :tag => "ol",
|
359
374
|
:attributes => { :id => "commentList"},
|
@@ -2,26 +2,27 @@ module XMLRPC
|
|
2
2
|
class XMLRPC::Client
|
3
3
|
attr_reader :method_name, :args
|
4
4
|
attr_accessor :uri
|
5
|
+
$xmlrpc_pings = []
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
end
|
8
9
|
|
9
10
|
def self.new2(uri)
|
10
|
-
|
11
|
+
$xmlrpc_pings ||= []
|
11
12
|
client = new
|
12
13
|
client.uri = uri
|
13
14
|
client
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.pings
|
17
|
-
|
18
|
+
$xmlrpc_pings
|
18
19
|
end
|
19
20
|
|
20
21
|
def call(name, *args)
|
21
22
|
@method_name = name
|
22
23
|
@args = *args
|
23
|
-
|
24
|
-
|
24
|
+
$xmlrpc_pings ||= []
|
25
|
+
$xmlrpc_pings << self
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
data/test/unit/article_test.rb
CHANGED
@@ -15,10 +15,10 @@ class ArticleTest < Test::Unit::TestCase
|
|
15
15
|
assert @articles.include?(i.is_a?(Symbol) ? contents(i) : i)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def test_blog
|
20
20
|
a = Article.new
|
21
|
-
|
21
|
+
|
22
22
|
assert_equal(1, a.blog_id)
|
23
23
|
assert_kind_of(Blog, a.blog)
|
24
24
|
end
|
@@ -119,10 +119,10 @@ class ArticleTest < Test::Unit::TestCase
|
|
119
119
|
|
120
120
|
assert_kind_of Article,b
|
121
121
|
assert_equal 0, b.tags.size
|
122
|
-
|
122
|
+
|
123
123
|
c = Article.new(:title => 'Foo', :keywords => 'test "tag test" web2.0')
|
124
124
|
c.keywords_to_tags
|
125
|
-
|
125
|
+
|
126
126
|
assert_equal 3, c.tags.size
|
127
127
|
assert_equal ['test', 'tagtest', 'web2.0'].sort, c.tags.collect(&:name).sort
|
128
128
|
end
|
@@ -248,4 +248,16 @@ class ArticleTest < Test::Unit::TestCase
|
|
248
248
|
assert_equal(2, Article.find_all_by_date(2004,03).size)
|
249
249
|
assert_equal(1, Article.find_all_by_date(2004,03,01).size)
|
250
250
|
end
|
251
|
+
|
252
|
+
def test_withdrawal
|
253
|
+
art = Article.find(contents(:article1).id)
|
254
|
+
assert art.published?
|
255
|
+
assert ! art.withdrawn?
|
256
|
+
art.withdraw!
|
257
|
+
assert ! art.published?
|
258
|
+
assert art.withdrawn?
|
259
|
+
art.reload
|
260
|
+
assert ! art.published?
|
261
|
+
assert art.withdrawn?
|
262
|
+
end
|
251
263
|
end
|
data/test/unit/comment_test.rb
CHANGED
@@ -27,49 +27,51 @@ class CommentTest < Test::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_reject_spam_rbl
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
cmt = Comment.new do |c|
|
31
|
+
c.author = "Spammer"
|
32
|
+
c.body = %{This is just some random text. <a href="http://chinaaircatering.com">without any senses.</a>. Please disregard.}
|
33
|
+
c.url = "http://buy-computer.us"
|
34
|
+
c.ip = "212.42.230.206"
|
35
|
+
end
|
36
|
+
assert cmt.spam?
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_not_spam_but_rbl_lookup_succeeds
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
cmt = Comment.new do |c|
|
41
|
+
c.author = "Not a Spammer"
|
42
|
+
c.body = "Useful commentary!"
|
43
|
+
c.url = "http://www.bofh.org.uk"
|
44
|
+
c.ip = "10.10.10.10"
|
45
|
+
end
|
46
|
+
assert !cmt.spam?
|
47
47
|
end
|
48
48
|
|
49
49
|
def test_reject_spam_pattern
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
cmt = Comment.new do |c|
|
51
|
+
c.author = "Another Spammer"
|
52
|
+
c.body = "Texas hold-em poker crap"
|
53
|
+
c.url = "http://texas.hold-em.us"
|
54
|
+
end
|
55
|
+
assert cmt.spam?
|
56
56
|
end
|
57
57
|
|
58
58
|
def test_reject_spam_uri_limit
|
59
|
-
c = Comment.new
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
c = Comment.new do |c|
|
60
|
+
c.author = "Yet Another Spammer"
|
61
|
+
c.body = %{ <a href="http://www.one.com/">one</a> <a href="http://www.two.com/">two</a> <a href="http://www.three.com/">three</a> <a href="http://www.four.com/">four</a> }
|
62
|
+
c.url = "http://www.uri-limit.com"
|
63
|
+
c.ip = "123.123.123.123"
|
64
|
+
end
|
64
65
|
|
65
|
-
|
66
|
+
assert c.spam?
|
66
67
|
end
|
67
68
|
|
68
69
|
def test_reject_article_age
|
69
|
-
c = Comment.new
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
c = Comment.new do |c|
|
71
|
+
c.author = "Old Spammer"
|
72
|
+
c.body = "Old trackback body"
|
73
|
+
c.article = contents(:inactive_article)
|
74
|
+
end
|
73
75
|
|
74
76
|
assert ! c.save
|
75
77
|
assert c.errors.invalid?('article_id')
|
@@ -93,10 +95,11 @@ class CommentTest < Test::Unit::TestCase
|
|
93
95
|
end
|
94
96
|
|
95
97
|
def test_xss_rejection
|
96
|
-
c = Comment.new
|
97
|
-
|
98
|
-
|
99
|
-
|
98
|
+
c = Comment.new do |c|
|
99
|
+
c.body = "Test foo <script>do_evil();</script>"
|
100
|
+
c.author = 'Bob'
|
101
|
+
c.article_id = 1
|
102
|
+
end
|
100
103
|
|
101
104
|
# Test each filter to make sure that we don't allow scripts through.
|
102
105
|
# Yes, this is ugly.
|
@@ -114,7 +117,26 @@ class CommentTest < Test::Unit::TestCase
|
|
114
117
|
c = Comment.find(contents(:comment2).id)
|
115
118
|
assert c.withdraw!
|
116
119
|
assert ! c.published?
|
117
|
-
assert c.
|
120
|
+
assert c.spam?
|
121
|
+
c.reload
|
118
122
|
assert ! c.published?
|
123
|
+
assert c.spam?
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_published
|
127
|
+
a = Article.new(:title => 'foo', :blog_id => 1)
|
128
|
+
assert a.save
|
129
|
+
|
130
|
+
assert_equal 0, a.published_comments.size
|
131
|
+
c = a.comments.build(:body => 'foo', :author => 'bob', :published => true, :published_at => Time.now)
|
132
|
+
assert c.save
|
133
|
+
assert c.published?
|
134
|
+
a.reload
|
135
|
+
|
136
|
+
assert_equal 1, a.published_comments.size
|
137
|
+
c.withdraw!
|
138
|
+
|
139
|
+
a = Article.new(:title => 'foo', :blog_id => 1)
|
140
|
+
assert_equal 0, a.published_comments.size
|
119
141
|
end
|
120
142
|
end
|
@@ -34,7 +34,7 @@ class ContentState::FactoryTest < Test::Unit::TestCase
|
|
34
34
|
def test_write_new_state
|
35
35
|
content = MockContent.new(true)
|
36
36
|
|
37
|
-
|
37
|
+
ContentState::New.instance.enter_hook(content)
|
38
38
|
|
39
39
|
assert_equal false, content.published?
|
40
40
|
assert_nil content.published_at
|
@@ -42,34 +42,35 @@ class ContentState::FactoryTest < Test::Unit::TestCase
|
|
42
42
|
|
43
43
|
def test_write_publication_pending_state
|
44
44
|
content = MockContent.new(true, true, 1.hour.from_now)
|
45
|
-
|
45
|
+
ContentState::PublicationPending.instance.enter_hook(content)
|
46
46
|
assert_equal false, content.published?
|
47
47
|
assert content.published_at > Time.now
|
48
48
|
end
|
49
49
|
|
50
50
|
def test_write_draft_state
|
51
51
|
content = MockContent.new(true, nil, nil)
|
52
|
-
|
52
|
+
ContentState::Draft.instance.enter_hook(content)
|
53
53
|
assert_equal false, content.published
|
54
54
|
assert_nil content.published_at
|
55
55
|
end
|
56
56
|
|
57
57
|
def test_write_just_published_state
|
58
58
|
content = MockContent.new(true, nil, nil)
|
59
|
-
|
59
|
+
ContentState::JustPublished.instance.enter_hook(content)
|
60
60
|
assert_equal true, content.published
|
61
61
|
assert content.published_at <= Time.now
|
62
62
|
|
63
63
|
published_at = 10.minutes.ago
|
64
64
|
content = MockContent.new(true, nil, published_at)
|
65
|
-
|
65
|
+
ContentState::JustPublished.instance.enter_hook(content)
|
66
66
|
assert_equal true, content.published
|
67
67
|
assert_equal published_at, content.published_at
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_write_published_state
|
71
71
|
content = MockContent.new
|
72
|
-
assert ContentState::Published.instance.
|
72
|
+
assert ContentState::Published.instance.enter_hook(content)
|
73
|
+
assert_equal true, content.published
|
73
74
|
end
|
74
75
|
|
75
76
|
class MockContent < Struct.new(:new_record, :published, :published_at)
|
data/test/unit/ping_test.rb
CHANGED
@@ -33,6 +33,20 @@ class PingTest < Test::Unit::TestCase
|
|
33
33
|
assert_pingback_sent
|
34
34
|
end
|
35
35
|
|
36
|
+
def test_ping_sent_on_save
|
37
|
+
Net::HTTP.next_response = self
|
38
|
+
|
39
|
+
art = Blog.default.articles.build \
|
40
|
+
:body => %{<link rel="pingback" href="http://anotherblog.org/xml-rpc" />},
|
41
|
+
:title => 'Test the pinging',
|
42
|
+
:published => true
|
43
|
+
assert art.save
|
44
|
+
sent_ping = XMLRPC::Client.pings.last
|
45
|
+
assert !art.just_published?
|
46
|
+
art.reload
|
47
|
+
assert !art.just_published?
|
48
|
+
end
|
49
|
+
|
36
50
|
def assert_pingback_sent
|
37
51
|
Net::HTTP.next_response = self
|
38
52
|
ping = contents(:article1).pings.build("url" =>
|
data/test/unit/trackback_test.rb
CHANGED
@@ -18,26 +18,27 @@ class TrackbackTest < Test::Unit::TestCase
|
|
18
18
|
assert tb.save
|
19
19
|
assert tb.errors.empty?
|
20
20
|
assert tb.guid.size > 15
|
21
|
-
|
21
|
+
assert !tb.spam?
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_reject_spam_rbl
|
25
|
-
tb = Trackback.new
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
tb = Trackback.new do |tb|
|
26
|
+
tb.blog_name = "Spammer"
|
27
|
+
tb.title = "Spammy trackback"
|
28
|
+
tb.excerpt = %{This is just some random text. <a href="http://chinaaircatering.com">without any senses.</a>. Please disregard.}
|
29
|
+
tb.url = "http://buy-computer.us"
|
30
|
+
tb.ip = "212.42.230.206"
|
31
|
+
end
|
32
|
+
|
33
|
+
assert tb.spam?
|
33
34
|
end
|
34
35
|
|
35
36
|
def test_reject_spam_pattern
|
36
|
-
tb = Trackback.new
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
tb = Trackback.new do |tb|
|
38
|
+
tb.blog_name = "Another Spammer"
|
39
|
+
tb.title = "Spammy trackback"
|
40
|
+
tb.excerpt = "Texas hold-em poker crap"
|
41
|
+
end
|
42
|
+
assert tb.spam?
|
42
43
|
end
|
43
44
|
end
|