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
@@ -20,7 +20,7 @@ class Admin::CommentsController < Admin::BaseController
20
20
 
21
21
  if request.post? and @comment.save
22
22
  # We should probably wave a spam filter over this, but for now, just mark it as published.
23
- @comment.published = true
23
+ @comment.mark_as_ham!
24
24
  flash[:notice] = 'Comment was successfully created.'
25
25
  redirect_to :action => 'show', :id => @comment.id
26
26
  end
@@ -78,9 +78,7 @@ class Admin::ContentController < Admin::BaseController
78
78
  def new_or_edit
79
79
  get_or_build_article
80
80
  params[:article] ||= {}
81
- # params[:article].reverse_merge!('allow_comments' => this_blog.default_allow_comments,
82
- # 'allow_pings' => this_blog.default_allow_pings,
83
- # 'published' => true)
81
+
84
82
  @article.attributes = (params[:article])
85
83
  setup_categories
86
84
  @selected = @article.categories.collect { |c| c.id }
@@ -1,67 +1,72 @@
1
+
2
+
1
3
  class Admin::FeedbackController < Admin::BaseController
4
+ model :comment, :trackback
5
+
2
6
  def index
3
- conditions = ["(contents.type = 'Comment' or contents.type = 'Trackback')"]
7
+ conditions = ['1=1', {}]
4
8
 
5
9
  if params[:search]
6
- search_sql = "%#{params[:search]}%"
7
- conditions.first << ' and (url like ? or author like ? or title like ? or ip like ? or email like ?)'
8
- 5.times { conditions.push search_sql }
10
+ conditions.first << ' and (url like :pattern or author like :pattern or title like :pattern or ip like :pattern or email like :pattern)'
11
+ conditions.last.merge!(:pattern => "%#{params[:search]}%")
9
12
  end
10
13
 
11
14
  if params[:published] == 'f'
12
- conditions.first << ' and (published = ?)'
13
- conditions.push false
15
+ conditions.first << ' and (published = :published)'
16
+ conditions.last.merge!(:published => false)
14
17
  end
15
18
 
16
- @pages, @feedback = paginate(:contents,
17
- :order => 'contents.created_at desc',
19
+ @pages, @feedback = paginate(:feedback,
20
+ :order => 'contents.created_at desc',
18
21
  :conditions => conditions,
19
22
  :per_page => 40)
20
-
23
+
21
24
  render_action 'list'
22
25
  end
23
-
26
+
24
27
  def delete
25
28
  if request.post?
26
- feedback = Content.find(params[:id])
27
- if feedback.kind_of? Comment or feedback.kind_of? Trackback
28
- feedback.destroy
29
+ begin
30
+ Feedback.destroy(params[:id])
29
31
  flash[:notice] = "Deleted"
30
- else
32
+ rescue ActiveRecord::RecordNotFound
31
33
  flash[:notice] = "Not found"
32
34
  end
33
35
  end
34
36
  redirect_to :action => 'index', :page => params[:page], :search => params[:search]
35
37
  end
36
-
38
+
37
39
  def bulkops
38
- STDERR.puts "Bulkops: #{params.inspect}"
39
-
40
40
  ids = (params[:feedback_check]||{}).keys.map(&:to_i)
41
-
41
+
42
42
  case params[:commit]
43
43
  when 'Delete Checked Items'
44
44
  count = 0
45
45
  ids.each do |id|
46
- count += Content.delete(id)
46
+ count += Feedback.delete(id) ## XXX Should this be #destroy?
47
47
  end
48
48
  flash[:notice] = "Deleted #{count} item(s)"
49
- when 'Publish Checked Items'
49
+
50
+ # Sweep cache
51
+ PageCache.sweep_all
52
+ expire_fragment(/.*/)
53
+ when 'Mark Checked Items as Ham'
54
+ ids.each do |id|
55
+ feedback = Feedback.find(id)
56
+ feedback.mark_as_ham!
57
+ end
58
+ flash[:notice]= "Marked #{ids.size} item(s) as Ham"
59
+ when 'Mark Checked Items as Spam'
50
60
  ids.each do |id|
51
- feedback = Content.find(id)
52
- feedback.attributes[:published] = true
53
- feedback.set_spam(false)
54
- feedback.save
61
+ feedback = Feedback.find(id)
62
+ feedback.mark_as_spam!
55
63
  end
56
- flash[:notice]= "Published #{ids.size} item(s)"
57
- when 'Unpublish Checked Items'
64
+ flash[:notice]= "Marked #{ids.size} item(s) as Spam"
65
+ when 'Confirm Classification of Checked Items'
58
66
  ids.each do |id|
59
- feedback = Content.find(id)
60
- feedback.withdraw!
61
- feedback.set_spam(true)
62
- feedback.save
67
+ Feedback.find(id).confirm_classification!
63
68
  end
64
- flash[:notice]= "Unpublished #{ids.size} item(s)"
69
+ flash[:notice] = "Confirmed classification of #{ids.size} item(s)"
65
70
  else
66
71
  flash[:notice] = "Not implemented"
67
72
  end
@@ -53,8 +53,19 @@ class Admin::SidebarController < Admin::BaseController
53
53
  params[:configure] ||= []
54
54
  Sidebar.update_all('active_position = null')
55
55
  flash[:sidebars].each do |id|
56
- Sidebar.find(id).update_attributes(:config => params[:configure][id.to_s],
57
- :active_position => position)
56
+ sidebar = Sidebar.find(id)
57
+
58
+ # If it's a checkbox and unchecked, convert the 0 to false
59
+ # This is ugly. Anyone have an improvement?
60
+ params[:configure][id.to_s].each do |k,v|
61
+ field = sidebar.sidebar_controller.fields.detect { |f| f.key == k }
62
+ if v == "0" && field.is_a?(Sidebars::Field::CheckBoxField)
63
+ params[:configure][id.to_s][k] = false
64
+ end
65
+ end
66
+
67
+ sidebar.update_attributes(:config => params[:configure][id.to_s],
68
+ :active_position => position)
58
69
  position += 1
59
70
  end
60
71
  Sidebar.delete_all('active_position is null')
@@ -10,7 +10,8 @@ class Admin::UsersController < Admin::BaseController
10
10
  end
11
11
 
12
12
  def show
13
- @user = User.find(params[:id])
13
+ @user = User.find(params[:id], :include => [ :articles ])
14
+ @articles = @user.articles
14
15
  end
15
16
 
16
17
  def new
@@ -27,12 +27,12 @@ class ArticlesController < ContentController
27
27
  @articles = Article.find( :all,
28
28
  :offset => @pages.current.offset,
29
29
  :limit => @pages.items_per_page,
30
- :order => "contents.published_at DESC",
30
+ :order => "contents.published_at DESC",
31
31
  :include => [:categories, :tags, :user, :blog],
32
32
  :conditions =>
33
33
  ['published = ? AND contents.published_at < ? AND blog_id = ?',
34
34
  true, Time.now, this_blog.id]
35
- )
35
+ )
36
36
  end
37
37
 
38
38
  def search
@@ -94,23 +94,14 @@ class ArticlesController < ContentController
94
94
 
95
95
  if request.post?
96
96
  begin
97
- params[:comment].merge!({:ip => request.remote_ip,
98
- :published => true })
99
97
  @article = this_blog.published_articles.find(params[:id])
100
- @comment = @article.comments.build(params[:comment])
101
- @comment.user = session[:user]
102
-
103
- spam_options = {
104
- :user_agent => request.env['HTTP_USER_AGENT'],
105
- :referrer => request.env['HTTP_REFERER'],
106
- :permalink => this_blog.article_url(@article, false)}
107
-
108
- if @comment.is_spam? spam_options
109
- STDERR.puts "Moderating comment as spam!"
110
- @comment.withdraw
111
- end
112
-
113
- @comment.save!
98
+ params[:comment].merge!({:ip => request.remote_ip,
99
+ :published => true,
100
+ :user => session[:user],
101
+ :user_agent => request.env['HTTP_USER_AGENT'],
102
+ :referrer => request.env['HTTP_REFERER'],
103
+ :permalink => this_blog.article_url(@article, false)})
104
+ @comment = @article.comments.create!(params[:comment])
114
105
  add_to_cookies(:author, @comment.author)
115
106
  add_to_cookies(:url, @comment.url)
116
107
 
@@ -165,7 +156,7 @@ class ArticlesController < ContentController
165
156
  render :nothing => true, :status => 404
166
157
  end
167
158
  end
168
-
159
+
169
160
  def markup_help
170
161
  render :text => TextFilter.find(params[:id]).commenthelp
171
162
  end
@@ -65,7 +65,7 @@ class XmlController < ContentController
65
65
 
66
66
  protected
67
67
 
68
- def fetch_items(association, order='created_at DESC', limit=nil)
68
+ def fetch_items(association, order='published_at DESC', limit=nil)
69
69
  if association.instance_of?(Symbol)
70
70
  association = this_blog.send(association)
71
71
  end
@@ -89,7 +89,7 @@ class XmlController < ContentController
89
89
 
90
90
  def prep_article
91
91
  article = this_blog.articles.find(params[:id])
92
- fetch_items(article.comments, 'created_at DESC', 25)
92
+ fetch_items(article.comments, 'published_at DESC', 25)
93
93
  @items.unshift(article)
94
94
  @feed_title << ": #{article.title}"
95
95
  @link = article_url(article, false)
@@ -1,5 +1,9 @@
1
1
  module Admin::BaseHelper
2
2
 
3
+ def state_class(item)
4
+ item.state.memento.underscore.sub(/.*\//, '')
5
+ end
6
+
3
7
  def render_flash
4
8
  output = []
5
9
 
@@ -14,10 +18,10 @@ module Admin::BaseHelper
14
18
  output = []
15
19
 
16
20
  for key,value in @tasks
17
- output << "<a href=\"#{value}\">#{key}</a>"
18
- end if @tasks
21
+ output << "<a href=\"#{value}\">#{key}</a>"
22
+ end if @tasks
19
23
 
20
- output.join("<br/>\n")
24
+ output.join("<br/>\n")
21
25
  end
22
26
 
23
27
  def current_user_notice
@@ -40,12 +40,12 @@ module ApplicationHelper
40
40
  end
41
41
 
42
42
  def comments_link(article)
43
- article_link(pluralize(article.comments.size, "comment"),
43
+ article_link(pluralize(article.published_comments.size, "comment"),
44
44
  article, 'comments')
45
45
  end
46
46
 
47
47
  def trackbacks_link(article)
48
- article_link(pluralize(article.trackbacks.size, "trackback"),
48
+ article_link(pluralize(article.published_trackbacks.size, "trackback"),
49
49
  article, 'trackbacks')
50
50
  end
51
51
 
@@ -42,7 +42,8 @@ module ArticlesHelper
42
42
 
43
43
  def page_title
44
44
  if @page_title
45
- @page_title
45
+ # this is where the page title prefix (string) should go
46
+ (this_blog.title_prefix ? "#{this_blog.blog_name || "Typo"} : " : '') + @page_title
46
47
  else
47
48
  this_blog.blog_name || "Typo"
48
49
  end
@@ -151,10 +152,10 @@ module ArticlesHelper
151
152
  end
152
153
 
153
154
  def ul_tag_for(grouping_class)
154
- case grouping_class
155
- when Tag
155
+ case
156
+ when grouping_class == Tag
156
157
  %{<ul id="taglist" class="tags">}
157
- when Category
158
+ when grouping_class == Category
158
159
  %{<ul class="categorylist">}
159
160
  else
160
161
  '<ul>'
@@ -37,9 +37,13 @@ class Article < Content
37
37
  urls
38
38
  end
39
39
 
40
- def really_send_pings(serverurl = blog.server_url, articleurl = location(nil, false))
40
+ def really_send_pings(serverurl = blog.server_url, articleurl = nil)
41
41
  return unless blog.send_outbound_pings
42
42
 
43
+ # Moved the default value for articleurl out of the method declaration to
44
+ # avoid unnecessary evaluations of the #location() method.
45
+ articleurl ||= location(nil, false)
46
+
43
47
  weblogupdatesping_urls = blog.ping_urls.gsub(/ +/,'').split(/[\n\r]+/)
44
48
  pingback_or_trackback_urls = self.html_urls
45
49
 
@@ -52,7 +56,7 @@ class Article < Content
52
56
 
53
57
  if weblogupdatesping_urls.include?(url)
54
58
  ping.send_weblogupdatesping(serverurl, articleurl)
55
- else pingback_or_trackback_urls.include?(url)
59
+ elsif pingback_or_trackback_urls.include?(url)
56
60
  ping.send_pingback_or_trackback(articleurl)
57
61
  end
58
62
  end
@@ -142,7 +146,7 @@ class Article < Content
142
146
  if user.notify_via_jabber?
143
147
  JabberNotify.send_message(user, "New post",
144
148
  "A new message was posted to #{blog.blog_name}",
145
- content.body_html)
149
+ body_html)
146
150
  end
147
151
  end
148
152
 
@@ -158,17 +162,20 @@ class Article < Content
158
162
  end
159
163
  end
160
164
 
165
+ def published_comments
166
+ comments.select {|c| c.published?}
167
+ end
168
+
169
+ def published_trackbacks
170
+ trackbacks.select {|c| c.published?}
171
+ end
172
+
161
173
  protected
162
174
 
163
175
  before_create :set_defaults, :create_guid, :add_notifications
164
176
  before_save :set_published_at
165
177
  after_save :keywords_to_tags
166
178
 
167
- def correct_counts
168
- self.comments_count = self.comments_count
169
- self.trackbacks_count = self.trackbacks_count
170
- end
171
-
172
179
  def set_published_at
173
180
  if self.published and self[:published_at].nil?
174
181
  self[:published_at] = self.created_at || Time.now
@@ -179,7 +186,6 @@ class Article < Content
179
186
  if self.attributes.include?("permalink") and self.permalink.blank?
180
187
  self.permalink = self.stripped_title
181
188
  end
182
- correct_counts
183
189
  if blog && self.allow_comments.nil?
184
190
  self.allow_comments = blog.default_allow_comments
185
191
  end
@@ -187,7 +193,7 @@ class Article < Content
187
193
  if blog && self.allow_pings.nil?
188
194
  self.allow_pings = blog.default_allow_pings
189
195
  end
190
-
196
+
191
197
  true
192
198
  end
193
199
 
@@ -2,9 +2,9 @@
2
2
  # This isn't enabled yet, but it will be soon...
3
3
  class BlogRequest
4
4
  include Reloadable
5
-
5
+
6
6
  attr_accessor :protocol, :host_with_port, :path, :symbolized_path_parameters, :relative_url_root
7
-
7
+
8
8
  def initialize(root)
9
9
  @protocol = @host_with_port = @path = ''
10
10
  @symbolized_path_parameters = {}
@@ -37,6 +37,7 @@ class Blog < ActiveRecord::Base
37
37
  # Description
38
38
  setting :blog_name, :string, 'My Shiny Weblog!'
39
39
  setting :blog_subtitle, :string, ''
40
+ setting :title_prefix, :boolean, false
40
41
  setting :geourl_location, :string, ''
41
42
  setting :canonical_server_url, :string, ''
42
43
 
@@ -86,13 +87,6 @@ class Blog < ActiveRecord::Base
86
87
  article_id = settings[:id]
87
88
  settings.delete(:id)
88
89
  trackback = published_articles.find(article_id).trackbacks.create!(settings)
89
-
90
- if trackback.is_spam?
91
- STDERR.puts "Moderating trackback as spam!"
92
- trackback.withdraw!
93
- end
94
-
95
- trackback
96
90
  end
97
91
 
98
92
 
@@ -161,7 +155,7 @@ class Blog < ActiveRecord::Base
161
155
  end
162
156
 
163
157
  def article_url(article, only_path = true, anchor = nil)
164
- url_for(:year => article.published_at.year,
158
+ url_for(:year => article.published_at.year,
165
159
  :month => sprintf("%.2d", article.published_at.month),
166
160
  :day => sprintf("%.2d", article.published_at.day),
167
161
  :title => article.permalink, :anchor => anchor,
@@ -2,22 +2,18 @@ require_dependency 'spam_protection'
2
2
  require 'sanitize'
3
3
  require 'timeout'
4
4
 
5
- class Comment < Content
6
- include TypoGuid
5
+ class Comment < Feedback
6
+ belongs_to :article
7
7
 
8
8
  content_fields :body
9
9
 
10
- belongs_to :article, :counter_cache => true
11
10
  belongs_to :user
12
11
 
13
12
  validates_presence_of :author, :body
14
- validates_age_of :article_id
15
- validate_on_create :check_article_is_open_to_comments
16
13
 
17
-
18
- def self.default_order
19
- 'created_at ASC'
20
- end
14
+ attr_accessor :user_agent
15
+ attr_accessor :referrer
16
+ attr_accessor :permalink
21
17
 
22
18
  def notify_user_via_email(controller, user)
23
19
  if user.notify_via_email?
@@ -37,17 +33,12 @@ class Comment < Content
37
33
  users
38
34
  end
39
35
 
40
- def location(anchor=:ignored, only_path=true)
41
- blog.url_for(article, "comment-#{id}", only_path)
42
- end
43
-
44
36
  protected
45
37
 
46
- def check_article_is_open_to_comments
47
- return unless article
48
- unless article.allow_comments?
49
- errors.add(:article, "Article is not open to comments")
50
- end
38
+ def article_allows_feedback?
39
+ return true if article.allow_comments?
40
+ errors.add(:article, "Article is not open to comments")
41
+ false
51
42
  end
52
43
 
53
44
  def body_html_postprocess(value, controller)
@@ -58,28 +49,18 @@ class Comment < Content
58
49
  'comment_text_filter'
59
50
  end
60
51
 
61
- before_create :create_guid
62
- before_save :correct_url, :make_nofollow
63
-
64
- def correct_url
65
- unless url.to_s.empty?
66
- unless url =~ /^http\:\/\//
67
- self.url = "http://#{url}"
68
- end
69
- end
70
- end
71
-
72
52
  def make_nofollow
73
53
  self.author = author.nofollowify
74
54
  self.body_html = body_html.to_s.nofollowify
75
55
  end
76
-
77
- def akismet_options
78
- {:user_ip => ip, :comment_type => 'comment', :comment_author => author, :comment_author_email => email,
79
- :comment_author_url => url, :comment_content => body}
56
+
57
+ def originator
58
+ author
80
59
  end
81
-
82
- def spam_fields
83
- [:body, :url, :ip]
60
+
61
+ def additional_akismet_options
62
+ { :user_agent => user_agent,
63
+ :referrer => referrer,
64
+ :permalink => permalink }
84
65
  end
85
66
  end