typo 4.0.0 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
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