typo 4.0.0 → 4.0.1
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/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/app/models/content.rb
CHANGED
@@ -18,15 +18,15 @@ class Content < ActiveRecord::Base
|
|
18
18
|
has_many :triggers, :as => :pending_item, :dependent => :delete_all
|
19
19
|
|
20
20
|
before_save :state_before_save
|
21
|
-
after_save :post_trigger
|
21
|
+
after_save :post_trigger, :state_after_save
|
22
22
|
|
23
23
|
serialize :whiteboard
|
24
24
|
|
25
25
|
@@content_fields = Hash.new
|
26
26
|
@@html_map = Hash.new
|
27
27
|
|
28
|
-
def initialize(*args)
|
29
|
-
super(*args)
|
28
|
+
def initialize(*args, &block)
|
29
|
+
super(*args, &block)
|
30
30
|
set_default_blog
|
31
31
|
end
|
32
32
|
|
@@ -112,7 +112,11 @@ class Content < ActiveRecord::Base
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def state_before_save
|
115
|
-
|
115
|
+
state.before_save(self)
|
116
|
+
end
|
117
|
+
|
118
|
+
def state_after_save
|
119
|
+
state.after_save(self)
|
116
120
|
end
|
117
121
|
|
118
122
|
def html_map(field=nil); self.class.html_map(field); end
|
@@ -175,14 +179,23 @@ class Content < ActiveRecord::Base
|
|
175
179
|
self[:blog] ||= blog_id.to_i.zero? ? Blog.default : Blog.find(blog_id)
|
176
180
|
end
|
177
181
|
|
182
|
+
def state=(newstate)
|
183
|
+
if state
|
184
|
+
state.exit_hook(self, newstate)
|
185
|
+
end
|
186
|
+
@state = newstate
|
187
|
+
self[:state] = newstate.memento
|
188
|
+
newstate.enter_hook(self)
|
189
|
+
@state
|
190
|
+
end
|
191
|
+
|
178
192
|
def publish!
|
179
193
|
self.published = true
|
180
194
|
self.save!
|
181
195
|
end
|
182
196
|
|
183
197
|
def withdraw
|
184
|
-
self
|
185
|
-
self.published_at = nil
|
198
|
+
state.withdraw(self)
|
186
199
|
end
|
187
200
|
|
188
201
|
def withdraw!
|
@@ -203,10 +216,18 @@ class Content < ActiveRecord::Base
|
|
203
216
|
self[:published_at] || self[:created_at]
|
204
217
|
end
|
205
218
|
|
219
|
+
def published?
|
220
|
+
state.published?(self)
|
221
|
+
end
|
222
|
+
|
206
223
|
def just_published?
|
207
224
|
state.just_published?
|
208
225
|
end
|
209
226
|
|
227
|
+
def withdrawn?
|
228
|
+
state.withdrawn?
|
229
|
+
end
|
230
|
+
|
210
231
|
def publication_pending?
|
211
232
|
state.publication_pending?
|
212
233
|
end
|
@@ -227,53 +248,10 @@ class Content < ActiveRecord::Base
|
|
227
248
|
def send_notifications(controller = nil)
|
228
249
|
state.send_notifications(self, controller || blog.controller)
|
229
250
|
end
|
230
|
-
|
231
|
-
# is_spam? checks to see if this is spam. This really belongs in a 'feedback' class
|
232
|
-
# that is the parent of Comment and Trackback, but we aren't going to build one right
|
233
|
-
# now.
|
234
|
-
#
|
235
|
-
# options are passed on to Akismet. Recommended options (when available) are:
|
236
|
-
#
|
237
|
-
# :permalink => the article's URL
|
238
|
-
# :user_agent => the poster's UserAgent string
|
239
|
-
# :referer => the poster's Referer string
|
240
|
-
#
|
241
|
-
def is_spam?(options={})
|
242
|
-
return false unless blog.sp_global
|
243
|
-
|
244
|
-
sp = SpamProtection.new(blog)
|
245
|
-
spam = false
|
246
|
-
|
247
|
-
# Check fields against the blacklist.
|
248
|
-
spam_fields.each do |field|
|
249
|
-
spam ||= sp.is_spam? self[field]
|
250
|
-
end
|
251
|
+
end
|
251
252
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
akismet = Akismet.new(blog.sp_akismet_key,blog.canonical_server_url)
|
256
|
-
spam ||= akismet.commentCheck(akismet_options.merge(options))
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
spam == true
|
261
|
-
end
|
262
|
-
|
263
|
-
def set_spam(is_spam, options ={})
|
264
|
-
unless blog.sp_akismet_key.blank?
|
265
|
-
Timeout.timeout(5) do
|
266
|
-
akismet = Akismet.new(blog.sp_akismet_key,blog.canonical_server_url)
|
267
|
-
if is_spam
|
268
|
-
STDERR.puts "** submitting spam for #{id}"
|
269
|
-
akismet.submitSpam(akismet_options.merge(options))
|
270
|
-
else
|
271
|
-
STDERR.puts "** submitting ham for #{id}"
|
272
|
-
akismet.submitHam(akismet_options.merge(options))
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
253
|
+
class Object
|
254
|
+
def to_text_filter
|
255
|
+
TextFilter.find_by_name(self.to_s) || TextFilter.find_by_name('none')
|
276
256
|
end
|
277
257
|
end
|
278
|
-
|
279
|
-
class Object; def to_text_filter; TextFilter.find_by_name(self.to_s); end; end
|
@@ -1,4 +1,10 @@
|
|
1
1
|
module ContentState
|
2
|
+
class StateError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class StateNotSerializable < StateError
|
6
|
+
end
|
7
|
+
|
2
8
|
class Base
|
3
9
|
include Reloadable
|
4
10
|
|
@@ -14,12 +20,34 @@ module ContentState
|
|
14
20
|
self.class.to_s
|
15
21
|
end
|
16
22
|
|
23
|
+
def exit_hook(content, target_state)
|
24
|
+
logger.debug("#{content} leaving state #{self.memento}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def enter_hook(content)
|
28
|
+
logger.debug("#{content} entering state #{self.memento}")
|
29
|
+
end
|
30
|
+
|
17
31
|
def before_save(content)
|
18
|
-
serialize_on(content)
|
19
32
|
true
|
20
33
|
end
|
21
34
|
|
22
|
-
def
|
35
|
+
def after_save(content)
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def withdraw(content)
|
40
|
+
end
|
41
|
+
|
42
|
+
def mark_as_spam(content)
|
43
|
+
content.state = Factory.new(:just_marked_as_spam)
|
44
|
+
end
|
45
|
+
|
46
|
+
def mark_as_ham(content)
|
47
|
+
content.state = Factory.new(:just_marked_as_ham)
|
48
|
+
end
|
49
|
+
|
50
|
+
def published?(content)
|
23
51
|
false
|
24
52
|
end
|
25
53
|
|
@@ -35,6 +63,10 @@ module ContentState
|
|
35
63
|
false
|
36
64
|
end
|
37
65
|
|
66
|
+
def withdrawn?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
38
70
|
def after_save(content)
|
39
71
|
true
|
40
72
|
end
|
@@ -43,13 +75,24 @@ module ContentState
|
|
43
75
|
true
|
44
76
|
end
|
45
77
|
|
46
|
-
def send_notifications(content)
|
78
|
+
def send_notifications(content, controller)
|
47
79
|
true
|
48
80
|
end
|
49
81
|
|
50
82
|
def send_pings(content)
|
51
83
|
true
|
52
84
|
end
|
85
|
+
|
86
|
+
def is_spam?(content)
|
87
|
+
false
|
88
|
+
end
|
89
|
+
|
90
|
+
def logger
|
91
|
+
@logger ||= RAILS_DEFAULT_LOGGER || Logger.new(STDERR)
|
92
|
+
end
|
93
|
+
|
94
|
+
def confirm_classification(content)
|
95
|
+
end
|
53
96
|
end
|
54
97
|
end
|
55
98
|
|
@@ -2,18 +2,11 @@ module ContentState
|
|
2
2
|
class Draft < Base
|
3
3
|
include Reloadable
|
4
4
|
include Singleton
|
5
|
-
class << self
|
6
|
-
def derivable_from(content)
|
7
|
-
! content.new_record? &&
|
8
|
-
! content.published &&
|
9
|
-
content.published_at.nil?
|
10
|
-
end
|
11
|
-
end
|
12
5
|
|
13
|
-
def
|
6
|
+
def enter_hook(content)
|
7
|
+
super
|
14
8
|
content[:published] = false
|
15
9
|
content.published_at = nil
|
16
|
-
true
|
17
10
|
end
|
18
11
|
|
19
12
|
def change_published_state(content, boolean)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ContentState
|
2
|
+
class Ham < Base
|
3
|
+
include Reloadable
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def enter_hook(content)
|
7
|
+
super
|
8
|
+
content[:published] = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def published?(content)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_save(content)
|
16
|
+
content.report_as_ham
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def withdraw(content)
|
21
|
+
content.mark_as_spam
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
'Ham'
|
26
|
+
end
|
27
|
+
|
28
|
+
def mark_as_ham(content)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ContentState
|
2
|
+
class JustMarkedAsSpam < Spam
|
3
|
+
def enter_hook(content)
|
4
|
+
logger.debug("#{content} entering state Content::JustMarkedAsSpam")
|
5
|
+
content[:published] = false
|
6
|
+
end
|
7
|
+
|
8
|
+
def exit_hook(content, target_state)
|
9
|
+
logger.debug("#{content} leaving state Content::JustMarkedAsSpam")
|
10
|
+
end
|
11
|
+
|
12
|
+
def memento
|
13
|
+
'ContentState::Spam'
|
14
|
+
end
|
15
|
+
|
16
|
+
def after_save(content)
|
17
|
+
content.state = Spam.instance
|
18
|
+
super
|
19
|
+
content.report_as_spam
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ContentState
|
2
|
+
class JustPresumedHam < Base
|
3
|
+
include Reloadable
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def memento
|
7
|
+
'ContentState::PresumedHam'
|
8
|
+
end
|
9
|
+
|
10
|
+
def enter_hook(content)
|
11
|
+
logger.debug("#{content} entering state Content::JustPresumedHam")
|
12
|
+
content[:published] = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def exit_hook(content, target_state)
|
16
|
+
logger.debug("#{content} leaving state Content::JustPresumedHam")
|
17
|
+
end
|
18
|
+
|
19
|
+
def published?(content)
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_save(content)
|
24
|
+
content.state = PresumedHam.instance
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_notifications(content, controller)
|
28
|
+
content.interested_users.each do |user|
|
29
|
+
content.send_notification_to_user(controller, user)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def send_pings(content)
|
34
|
+
content.really_send_pings
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,23 +3,25 @@ module ContentState
|
|
3
3
|
include Reloadable
|
4
4
|
include Singleton
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
# We need to save the state as 'Published', but we need after_save
|
7
|
+
# to be handled by JustPublished. So, JustPublished tells Rails that
|
8
|
+
# it's *actually* Published and all shall be well.
|
9
|
+
def memento
|
10
|
+
'ContentState::Published'
|
12
11
|
end
|
13
12
|
|
14
13
|
def just_published?
|
15
14
|
true
|
16
15
|
end
|
17
16
|
|
17
|
+
def published?(content)
|
18
|
+
true
|
19
|
+
end
|
18
20
|
|
19
|
-
def
|
21
|
+
def enter_hook(content)
|
22
|
+
super
|
20
23
|
content[:published] = true
|
21
24
|
content[:published_at] ||= Time.now
|
22
|
-
true
|
23
25
|
end
|
24
26
|
|
25
27
|
def set_published_at(content, new_time)
|
@@ -43,5 +45,10 @@ module ContentState
|
|
43
45
|
def send_pings(content)
|
44
46
|
content.really_send_pings
|
45
47
|
end
|
48
|
+
|
49
|
+
def withdraw(content)
|
50
|
+
content[:published_at] = nil
|
51
|
+
content.state = Factory.new(:draft)
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
@@ -2,18 +2,11 @@ module ContentState
|
|
2
2
|
class New < Base
|
3
3
|
include Reloadable
|
4
4
|
include Singleton
|
5
|
-
class << self
|
6
|
-
def derivable_from(content)
|
7
|
-
content.new_record? &&
|
8
|
-
!content.published &&
|
9
|
-
content.published_at.nil?
|
10
|
-
end
|
11
|
-
end
|
12
5
|
|
13
|
-
def
|
6
|
+
def enter_hook(content)
|
7
|
+
super
|
14
8
|
content[:published] = false
|
15
9
|
content[:published_at] = nil
|
16
|
-
true
|
17
10
|
end
|
18
11
|
|
19
12
|
def before_save(content)
|
@@ -23,7 +16,7 @@ module ContentState
|
|
23
16
|
|
24
17
|
def change_published_state(content, boolean)
|
25
18
|
content[:published] = boolean
|
26
|
-
if
|
19
|
+
if boolean
|
27
20
|
content.state = JustPublished.instance
|
28
21
|
end
|
29
22
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ContentState
|
2
|
+
class PresumedHam < Base
|
3
|
+
include Reloadable
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def enter_hook(content)
|
7
|
+
super
|
8
|
+
content[:published] = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def published?(content)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def withdraw(content)
|
16
|
+
content.mark_as_spam
|
17
|
+
end
|
18
|
+
|
19
|
+
def confirm_classification(content)
|
20
|
+
content.mark_as_ham
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
'Ham?'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|