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.
Files changed (82) hide show
  1. data/app/controllers/admin/comments_controller.rb +1 -1
  2. data/app/controllers/admin/content_controller.rb +1 -3
  3. data/app/controllers/admin/feedback_controller.rb +36 -31
  4. data/app/controllers/admin/sidebar_controller.rb +13 -2
  5. data/app/controllers/admin/users_controller.rb +2 -1
  6. data/app/controllers/articles_controller.rb +10 -19
  7. data/app/controllers/xml_controller.rb +2 -2
  8. data/app/helpers/admin/base_helper.rb +7 -3
  9. data/app/helpers/application_helper.rb +2 -2
  10. data/app/helpers/articles_helper.rb +5 -4
  11. data/app/models/article.rb +16 -10
  12. data/app/models/blog.rb +4 -10
  13. data/app/models/comment.rb +17 -36
  14. data/app/models/content.rb +31 -53
  15. data/app/models/content_state/base.rb +46 -3
  16. data/app/models/content_state/draft.rb +2 -9
  17. data/app/models/content_state/ham.rb +31 -0
  18. data/app/models/content_state/just_marked_as_ham.rb +10 -0
  19. data/app/models/content_state/just_marked_as_spam.rb +23 -0
  20. data/app/models/content_state/just_presumed_ham.rb +37 -0
  21. data/app/models/content_state/just_published.rb +15 -8
  22. data/app/models/content_state/new.rb +3 -10
  23. data/app/models/content_state/presumed_ham.rb +27 -0
  24. data/app/models/content_state/presumed_spam.rb +31 -0
  25. data/app/models/content_state/publication_pending.rb +7 -9
  26. data/app/models/content_state/published.rb +10 -9
  27. data/app/models/content_state/spam.rb +23 -0
  28. data/app/models/content_state/unclassified.rb +29 -0
  29. data/app/models/content_state/withdrawn.rb +28 -0
  30. data/app/models/email_notifier.rb +0 -1
  31. data/app/models/feedback.rb +151 -0
  32. data/app/models/trackback.rb +22 -29
  33. data/app/views/admin/feedback/_item.rhtml +5 -5
  34. data/app/views/admin/feedback/list.rhtml +13 -11
  35. data/app/views/admin/general/index.rhtml +8 -4
  36. data/app/views/admin/users/show.rhtml +7 -1
  37. data/app/views/articles/read.rhtml +2 -2
  38. data/bin/typo +7 -6
  39. data/components/plugins/sidebars/recent_comments_controller.rb +1 -1
  40. data/config/environment.rb +2 -0
  41. data/db/migrate/046_fixup_forthcoming_publications.rb +1 -1
  42. data/db/migrate/048_remove_count_caching.rb +31 -0
  43. data/db/migrate/049_move_feedback_to_new_state_machine.rb +33 -0
  44. data/db/schema.mysql-v3.sql +3 -4
  45. data/db/schema.mysql.sql +3 -4
  46. data/db/schema.postgresql.sql +3 -4
  47. data/db/schema.rb +12 -17
  48. data/db/schema.sqlite.sql +3 -4
  49. data/db/schema.sqlserver.sql +3 -4
  50. data/db/schema_version +1 -1
  51. data/doc/Installer.txt +4 -0
  52. data/lib/jabber_notify.rb +6 -2
  53. data/lib/sidebars/plugin.rb +2 -1
  54. data/lib/tasks/release.rake +5 -4
  55. data/lib/typo_version.rb +1 -1
  56. data/public/stylesheets/administration.css +22 -2
  57. data/test/fixtures/blogs.yml +2 -0
  58. data/test/fixtures/contents.yml +7 -7
  59. data/test/functional/admin/users_controller_test.rb +3 -0
  60. data/test/functional/articles_controller_test.rb +16 -1
  61. data/test/mocks/test/xmlrpc_mock.rb +5 -4
  62. data/test/unit/article_test.rb +16 -4
  63. data/test/unit/comment_test.rb +57 -35
  64. data/test/unit/content_state/factory_test.rb +7 -6
  65. data/test/unit/ping_test.rb +14 -0
  66. data/test/unit/trackback_test.rb +16 -15
  67. metadata +26 -26
  68. data/config/database.yml-pgsql +0 -17
  69. data/config/database.yml.sqlite +0 -14
  70. data/config/mail.yml +0 -8
  71. data/config/mongrel.conf +0 -2
  72. data/db/converters/mt-import.rb +0 -72
  73. data/db/development_structure.sql +0 -691
  74. data/installer/rails-installer.rb +0 -527
  75. data/installer/rails-installer/commands.rb +0 -118
  76. data/installer/rails-installer/web-servers.rb +0 -110
  77. data/log/development.log-1 +0 -991
  78. data/log/development.log-2 +0 -422
  79. data/log/development.log-3 +0 -429
  80. data/log/development.log-4 +0 -174
  81. data/svk-commitP6cVv.tmp +0 -1
  82. data/vendor/ruby-mp3info/lib/mp3info.rb +0 -720
@@ -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
- self.state.before_save(self)
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.published = false
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
- # Attempt to use Akismet. Timeout after 5 seconds if we can't contact them.
253
- unless blog.sp_akismet_key.blank?
254
- Timeout.timeout(5) do
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 published?
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 serialize_on(content)
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,10 @@
1
+ module ContentState
2
+ class JustMarkedAsHam < JustPresumedHam
3
+ include Reloadable
4
+ include Singleton
5
+
6
+ def memento
7
+ 'ContentState::Ham'
8
+ end
9
+ end
10
+ 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
- class << self
7
- def derivable_from(content)
8
- content.new_record? &&
9
- content.published &&
10
- content[:published_at].nil?
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 serialize_on(content)
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 serialize_on(content)
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 content.published
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