radiant-comments-extension 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG +40 -0
  3. data/HELP_admin.markdown +52 -0
  4. data/HELP_designer.markdown +36 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +53 -0
  7. data/Rakefile +133 -0
  8. data/TODO +6 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/admin/comments_controller.rb +130 -0
  11. data/app/controllers/comments_controller.rb +59 -0
  12. data/app/helpers/admin/comments_helper.rb +7 -0
  13. data/app/models/akismet_spam_filter.rb +37 -0
  14. data/app/models/comment.rb +121 -0
  15. data/app/models/comment_mailer.rb +24 -0
  16. data/app/models/mollom_spam_filter.rb +52 -0
  17. data/app/models/simple_spam_filter.rb +38 -0
  18. data/app/models/spam_filter.rb +43 -0
  19. data/app/views/admin/comments/_comment.rhtml +34 -0
  20. data/app/views/admin/comments/_form.rhtml +36 -0
  21. data/app/views/admin/comments/edit.rhtml +5 -0
  22. data/app/views/admin/comments/index.rhtml +55 -0
  23. data/app/views/admin/pages/_comments.rhtml +0 -0
  24. data/app/views/admin/pages/_edit_comments_enabled.rhtml +8 -0
  25. data/app/views/admin/pages/_index_head_view_comments.rhtml +1 -0
  26. data/app/views/admin/pages/_index_view_comments.rhtml +11 -0
  27. data/app/views/comment_mailer/comment_notification.rhtml +21 -0
  28. data/app/views/comments/_comment.rhtml +1 -0
  29. data/app/views/comments/_form.rhtml +23 -0
  30. data/app/views/comments/_new.rhtml +5 -0
  31. data/autotest/discover.rb +3 -0
  32. data/comments_extension.rb +81 -0
  33. data/cucumber.yml +1 -0
  34. data/db/migrate/001_create_comments.rb +29 -0
  35. data/db/migrate/002_create_snippets.rb +115 -0
  36. data/db/migrate/003_change_filter_id_from_integer_to_string.rb +10 -0
  37. data/db/migrate/004_add_approval_columns.rb +13 -0
  38. data/db/migrate/005_add_mollomid_column.rb +11 -0
  39. data/db/migrate/006_move_config_to_migrations.rb +22 -0
  40. data/db/migrate/007_add_preference_for_simple_spamcheck.rb +12 -0
  41. data/features/support/env.rb +16 -0
  42. data/features/support/paths.rb +16 -0
  43. data/lib/akismet.rb +134 -0
  44. data/lib/comment_page_extensions.rb +41 -0
  45. data/lib/comment_tags.rb +338 -0
  46. data/lib/mollom.rb +246 -0
  47. data/lib/radiant-comments-extension.rb +0 -0
  48. data/lib/tasks/comments_extension_tasks.rake +68 -0
  49. data/public/images/admin/accept.png +0 -0
  50. data/public/images/admin/comment_edit.png +0 -0
  51. data/public/images/admin/comments.png +0 -0
  52. data/public/images/admin/comments_delete.png +0 -0
  53. data/public/images/admin/delete.png +0 -0
  54. data/public/images/admin/email.png +0 -0
  55. data/public/images/admin/error.png +0 -0
  56. data/public/images/admin/link.png +0 -0
  57. data/public/images/admin/page_white_edit.png +0 -0
  58. data/public/images/admin/table_save.png +0 -0
  59. data/public/images/admin/tick.png +0 -0
  60. data/public/stylesheets/admin/comments.css +41 -0
  61. data/radiant-comments-extension.gemspec +133 -0
  62. data/spec/controllers/admin/comments_controller_spec.rb +57 -0
  63. data/spec/controllers/admin/comments_routing_spec.rb +43 -0
  64. data/spec/controllers/page_postback_spec.rb +51 -0
  65. data/spec/datasets/comments_dataset.rb +7 -0
  66. data/spec/models/akismet_spam_filter_spec.rb +61 -0
  67. data/spec/models/comment_spec.rb +148 -0
  68. data/spec/models/comment_tags_spec.rb +55 -0
  69. data/spec/models/mollom_spam_filter_spec.rb +103 -0
  70. data/spec/models/simple_spam_filter_spec.rb +44 -0
  71. data/spec/models/spam_filter_spec.rb +38 -0
  72. data/spec/spec.opts +6 -0
  73. data/spec/spec_helper.rb +36 -0
  74. data/test/fixtures/users.yml +6 -0
  75. data/test/integration/comment_enabling_test.rb +18 -0
  76. data/test/test_helper.rb +24 -0
  77. data/test/unit/comment_test.rb +52 -0
  78. metadata +177 -0
@@ -0,0 +1,5 @@
1
+ <h1>Edit Comment on "<%= escape_once(@comment.page.title) %>"</h1>
2
+
3
+ <% form_for [:admin, @comment] do |f| %>
4
+ <%= render :partial => "form", :locals => {:f => f} %>
5
+ <% end %>
@@ -0,0 +1,55 @@
1
+ <% content_for :page_scripts do -%>
2
+ document.observe('dom:loaded', function(){
3
+ Event.addBehavior({
4
+ 'tr.comment td.content': function(event){
5
+ $(this).observe('click', function(event){
6
+ if($(this).down('blockquote.expanded')){
7
+ $(this).down('blockquote.expanded').toggle();
8
+ $(this).down('blockquote.short').toggle();
9
+ }
10
+ event.stop();
11
+ });
12
+ }
13
+ });
14
+ });
15
+ <% end %>
16
+ <%- include_stylesheet 'admin/comments' %>
17
+ <h1>
18
+ <% if @page -%>
19
+ <%= @page.comments.count %> <%= "#{params[:status].titleize} " if params[:status] %><%= pluralize(@page.comments.count, 'Comment') %> on <%= link_to @page.title, edit_admin_page_path(@page) %>
20
+ <% else -%>
21
+ <%= params[:status].titleize if params[:status] %> Comments
22
+ <% end -%>
23
+ </h1>
24
+
25
+ <ul id="comment-nav">
26
+ <li class="all"><%= link_or_span_unless_current("All", :status => 'all', :page_id => params[:page_id]) %></li>
27
+ <li class="approved"><%= link_or_span_unless_current("Approved", :status => "approved", :page_id => params[:page_id]) %></li>
28
+ <li class="unapproved"><%= link_or_span_unless_current("Unapproved", :status => "unapproved", :page_id => params[:page_id]) %></li>
29
+ <li class="csv"><%= link_to "Download CSV", :format => :csv %></li>
30
+ </ul>
31
+
32
+ <%= will_paginate @comments %>
33
+
34
+ <table id="comments" class="index" border="0" cellspacing="0" cellpadding="0">
35
+ <thead>
36
+ <tr>
37
+ <th>Content</th>
38
+ <th>Date</th>
39
+ <th>Author</th>
40
+ <% unless @page %><th>Page</th><% end %>
41
+ <th>Actions</th>
42
+ </tr>
43
+ </thead>
44
+ <tbody>
45
+ <%= render(:partial => "comment", :collection => @comments) || %Q[<tr><td class="note" colspan="#{@page ? 4 : 5}">No comments</td></tr>] %>
46
+ </tbody>
47
+ </table>
48
+
49
+ <%= will_paginate @comments %>
50
+
51
+ <% form_tag destroy_unapproved_admin_comments_url, :method => :delete do %>
52
+ <p><button type="submit" class="delete-unapproved"><%= image_tag("admin/comments_delete.png") %> Delete All Unapproved</button></p>
53
+ <% end %>
54
+
55
+ <p><small class="notice"><%= Comment.spam_filter.message %></small></p>
File without changes
@@ -0,0 +1,8 @@
1
+ <p style="clear:left">
2
+ <label for="page_enable_comments">Allow Comments on this page?</label>
3
+ <%= check_box "page", "enable_comments" %>
4
+
5
+ <small>
6
+ <%= link_to "Currently #{@page.comments_count} &mdash; View comments", admin_page_comments_path(:page_id => @page.id) unless @page.new_record? or @page.comments_count < 1 %>
7
+ </small>
8
+ </p>
@@ -0,0 +1 @@
1
+ <th class="comments">Comments</th>
@@ -0,0 +1,11 @@
1
+ <td class="comment_link">
2
+ <% if page.respond_to?('enable_comments') %>
3
+ <small>
4
+ <% if page.enable_comments %>
5
+ <%= link_to "#{page.comments_count} comments", admin_page_comments_path(:page_id => page.id) %>
6
+ <% else %>
7
+ <%= link_to "Enable", admin_page_enable_comments_path(:page_id => page.id), :method => :put %>
8
+ <% end %>
9
+ </small>
10
+ <% end %>
11
+ </td>
@@ -0,0 +1,21 @@
1
+ A new <%= @comment.ap_status %> comment has been posted on the <%= @site_name %> article <%= @comment.page.title %> (<%= @page_url %>)
2
+
3
+ Author : <%= @comment.author %> (IP: <%= @comment.author_ip %>)
4
+ E-mail : <%= @comment.author_email %>
5
+ URL : <%= @comment.author_url %>
6
+ Whois : http://ws.arin.net/cgi-bin/whois.pl?queryinput=<%= @comment.author_ip %>
7
+ Comment:
8
+
9
+
10
+ <%= @comment.content %>
11
+
12
+
13
+
14
+ You can see all comments on this post here:
15
+ <%= admin_page_comments_url(@comment.page) %>;
16
+
17
+ Approve it:
18
+ <%= approve_admin_comment_url(@comment) %>
19
+
20
+ View all comments awaiting approval:
21
+ <%= admin_comments_url(:status => :unapproved) %>
@@ -0,0 +1 @@
1
+ <%= comment.inspect %>
@@ -0,0 +1,23 @@
1
+ <h1>Comment Form</h1>
2
+
3
+ <div id="comment_form_container">
4
+
5
+ <fieldset class="comment_form">
6
+
7
+ <a name="comment_form"></a>
8
+
9
+ <%= f.text_field :author, :label => "Your Name (as you'd like it to appear on this comment)", :class => "regular" %>
10
+
11
+ <%= f.text_field :author_url %>
12
+
13
+ <%= f.text_field :author_email %>
14
+
15
+ <%= f.text_area :content, :label => "Your comment", :rows => 5, :class => "regular" %>
16
+
17
+ <%= submit_tag("Save comment", :class => "button", :id => "comment_submit_button") %>
18
+
19
+ <%= f.hidden_field :page_id %>
20
+
21
+ </fieldset>
22
+
23
+ </div>
@@ -0,0 +1,5 @@
1
+ <h1>Comment Form</h1>
2
+
3
+ <% form_for :comment, @comment, :url => {:controller => :comments, :action => :create} do |f| %>
4
+ <%= render :partial => "comments/form", :locals => {:f => f} %>
5
+ <% end %>
@@ -0,0 +1,3 @@
1
+ Autotest.add_discovery do
2
+ "rails"
3
+ end
@@ -0,0 +1,81 @@
1
+ class CommentsExtension < Radiant::Extension
2
+ version "#{File.read(File.expand_path(File.dirname(__FILE__)) + '/VERSION')}"
3
+ description "Adds blog-like comments and comment functionality to pages."
4
+ url "http://github.com/saturnflyer/radiant-comments"
5
+
6
+ define_routes do |map|
7
+ map.namespace :admin do |admin|
8
+ admin.connect 'comments/:status', :controller => 'comments', :status => 'unapproved', :conditions => { :method => :get }, :requirements => { :status => /all|unapproved|approved/ }
9
+ admin.connect 'comments/:status.:format', :controller => 'comments', :status => /all|approved|unapproved/, :conditions => { :method => :get }
10
+ admin.resources :comments, :member => { :remove => :get, :approve => :put, :unapprove => :put }, :collection => {:destroy_unapproved => :delete}
11
+ admin.page_enable_comments '/pages/:page_id/comments/enable', :controller => 'comments', :action => 'enable', :conditions => {:method => :put}
12
+ end
13
+ map.with_options(:controller => 'admin/comments') do |comments|
14
+ comments.connect 'admin/pages/:page_id/comments/:status', :status => /all|approved|unapproved/, :conditions => { :method => :get }
15
+ comments.connect 'admin/pages/:page_id/comments/:status.:format', :status => /all|approved|unapproved/, :conditions => { :method => :get }
16
+ comments.admin_page_comments 'admin/pages/:page_id/comments/:action'
17
+ comments.admin_page_comment 'admin/pages/:page_id/comments/:id/:action'
18
+ end
19
+ # This needs to be last, otherwise it hoses the admin routes.
20
+ map.resources :comments, :name_prefix => "page_", :path_prefix => "*url", :controller => "comments"
21
+ end
22
+
23
+ def activate
24
+ require 'sanitize'
25
+
26
+ Dir["#{File.dirname(__FILE__)}/app/models/*_filter.rb"].each do |file|
27
+ require file
28
+ end
29
+
30
+ Page.class_eval do
31
+ include CommentPageExtensions
32
+ include CommentTags
33
+ end
34
+
35
+ if admin.respond_to? :page
36
+ admin.page.edit.add :parts_bottom, "edit_comments_enabled", :before => "edit_timestamp"
37
+ admin.page.index.add :sitemap_head, "index_head_view_comments"
38
+ admin.page.index.add :node, "index_view_comments"
39
+ end
40
+
41
+ if self.respond_to? :tab
42
+ tab "Content" do
43
+ add_item('Comments', '/admin/comments')
44
+ end
45
+ else
46
+ admin.tabs.add "Comments", "/admin/comments", :visibility => [:all]
47
+ end
48
+ require "fastercsv"
49
+
50
+ ActiveRecord::Base.class_eval do
51
+ def self.to_csv(*args)
52
+ find(:all).to_csv(*args)
53
+ end
54
+
55
+ def export_columns(format = nil)
56
+ self.class.content_columns.map(&:name) - ['created_at', 'updated_at']
57
+ end
58
+
59
+ def to_row(format = nil)
60
+ export_columns(format).map { |c| self.send(c) }
61
+ end
62
+ end
63
+
64
+ Array.class_eval do
65
+ def to_csv(options = {})
66
+ return "" if first.nil?
67
+ if all? { |e| e.respond_to?(:to_row) }
68
+ header_row = first.export_columns(options[:format]).to_csv
69
+ content_rows = map { |e| e.to_row(options[:format]) }.map(&:to_csv)
70
+ ([header_row] + content_rows).join
71
+ else
72
+ FasterCSV.generate_line(self, options)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def deactivate
79
+ end
80
+
81
+ end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --format progress features --tags ~@proposed,~@in_progress
@@ -0,0 +1,29 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.column :page_id, :integer
5
+ t.column :author, :string
6
+ t.column :author_url, :string
7
+ t.column :author_email, :string
8
+ t.column :author_ip, :string
9
+ t.column :content, :text
10
+ t.column :content_html, :text
11
+ t.column :created_at, :datetime
12
+ t.column :updated_at, :datetime
13
+ t.column :filter_id, :integer
14
+ t.column :user_agent, :string
15
+ t.column :referrer, :string
16
+ end
17
+
18
+ add_column :pages, :enable_comments, :boolean, :default => false
19
+ add_column :pages, :comments_count, :integer, :default => 0
20
+ Page.reset_column_information
21
+ Page.update_all("comments_count = 0")
22
+ end
23
+
24
+ def self.down
25
+ drop_table :comments
26
+ remove_column :pages, :enable_comments
27
+ remove_column :pages, :comments_count
28
+ end
29
+ end
@@ -0,0 +1,115 @@
1
+ class CreateSnippets < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ # This code _WILL_ override snippets with the name comments, comment and comment_form
5
+ # if they exists.
6
+
7
+ # Comments snippet
8
+ Snippet.new do |s|
9
+ s.name = "comments"
10
+ s.content = <<CONTENT
11
+ <r:if_comments>
12
+ <div class="comments">
13
+ <h2>Comments</h2>
14
+ <r:comments:each>
15
+ <r:snippet name="comment" />
16
+ </r:comments:each>
17
+ </div>
18
+ </r:if_comments>
19
+ <r:snippet name="comment_form" />
20
+ CONTENT
21
+ end.save
22
+
23
+ # Comment snippet
24
+ Snippet.new do |s|
25
+ s.name = "comment"
26
+ s.content = <<CONTENT
27
+ <r:comments:field>
28
+ <div class="comment" id="comment-<r:id/>">
29
+ <p class="author">
30
+ <r:if_author_url><a href="<r:author_url/>" title="Visit <r:author/>'s website"></r:if_author_url>
31
+ <r:author/>
32
+ <r:if_author_url></a></r:if_author_url>
33
+ said on <r:date/>:
34
+ </p>
35
+
36
+ <div class="content_html"><r:content_html /></div>
37
+
38
+ <r:if_selected><p><em>
39
+ <r:if_approved>Thanks for your comment!</r:if_approved>
40
+ <r:unless_approved>Thanks for your comment, it has gone into the moderation queue and will be dealt with shortly.</r:unless_approved>
41
+ </em></p></r:if_selected>
42
+ </div>
43
+ </r:comments:field>
44
+ CONTENT
45
+ end.save
46
+
47
+ # comment_spam_block snippet
48
+ Snippet.new do |s|
49
+ s.name = 'comment_spam_block'
50
+ s.content = <<CONTENT
51
+ <r:random>
52
+ <r:error on="spam_answer"><p style="color:red">Answer <r:message /></p></r:error>
53
+ <r:option>
54
+ <p><label for="comment_spam_answer">What day of the week has the letter "h" in it's name?</label> (required)<br />
55
+ <r:spam_answer_tag answer="Thursday" /></p>
56
+ </r:option>
57
+ <r:option>
58
+ <p><label for="comment_spam_answer">Yellow and blue together make what color?</label> (required)<br />
59
+ <r:spam_answer_tag answer="green" /></p>
60
+ </r:option>
61
+ <r:option>
62
+ <p><label for="comment_spam_answer">What is SPAM spelled backwards?</label> (required)<br />
63
+ <r:spam_answer_tag answer="MAPS" /></p>
64
+ </r:option>
65
+ </r:random>
66
+ CONTENT
67
+ end.save
68
+
69
+ # Comment_form snippet
70
+ Snippet.new do |s|
71
+ s.name = "comment_form"
72
+ s.content = <<CONTENT
73
+ <r:page>
74
+ <r:if_enable_comments>
75
+ <r:comments:form>
76
+ <h3>Post a comment</h3>
77
+ <r:error><p style="color:red">Please correct the errors below.</p></r:error>
78
+ <p><label for="comment_author">Your Name</label><br />
79
+ <r:error on="author"><p style="color:red">Name <r:message /></p></r:error>
80
+ <r:text_field_tag name="author" id="author" class="required" /></p>
81
+
82
+ <p><label for="comment_author_email">Your Email Address</label> (required, but not displayed)<br />
83
+ <r:error on="author_email"><p style="color:red">Email <r:message /></p></r:error>
84
+ <r:text_field_tag name="author_email" class="required" /></p>
85
+
86
+ <p><label for="comment_author_url">Your Web Address</label> (optional)<br />
87
+ <r:error on="author_url"><p style="color:red">Web Address <r:message /></p></r:error>
88
+ <r:text_field_tag name="author_url" /></p>
89
+
90
+ <p><label for="comment_content">Your Comment</label><br />
91
+ <r:error on="content"><p style="color:red">Comment <r:message /></p></r:error>
92
+ <label for="comment_filter_id">Filter: <r:filter_box_tag name="filter_id" value="Textile" /></label><br />
93
+ <r:text_area_tag name="content" class="required" rows="9" cols="40" /></p>
94
+
95
+ <r:if_comments_simple_spam_filter_enabled>
96
+ <r:snippet name="comment_spam_block" />
97
+ </r:if_comments_simple_spam_filter_enabled>
98
+
99
+ <r:submit_tag name="submit" value="Save Comment" />
100
+
101
+ </r:comments:form>
102
+ </r:if_enable_comments>
103
+ </r:page>
104
+ CONTENT
105
+ end.save
106
+ end
107
+
108
+ def self.down
109
+
110
+ ["comments", "comment", "comment_form", "comment_spam_block"].each do |snippet|
111
+ Snippet.find_by_name(snippet).destroy rescue p "Could not destroy snippet #{snippet}"
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,10 @@
1
+ class ChangeFilterIdFromIntegerToString < ActiveRecord::Migration
2
+ def self.up
3
+ change_column "comments", "filter_id", :string, :limit => 25
4
+ end
5
+
6
+ def self.down
7
+ change_column "comments", "filter_id", :integer
8
+ end
9
+ end
10
+
@@ -0,0 +1,13 @@
1
+ # rake production radiant:extensions:comments:migrate
2
+ class AddApprovalColumns < ActiveRecord::Migration
3
+ def self.up
4
+ add_column :comments, :approved_at, :datetime
5
+ add_column :comments, :approved_by, :integer
6
+ end
7
+
8
+ def self.down
9
+ remove_column :comments, :approved_by
10
+ remove_column :comments, :approved_at
11
+ end
12
+ end
13
+
@@ -0,0 +1,11 @@
1
+ # rake production radiant:extensions:comments:migrate
2
+ class AddMollomidColumn < ActiveRecord::Migration
3
+ def self.up
4
+ add_column :comments, :mollom_id, :string
5
+ end
6
+
7
+ def self.down
8
+ remove_column :comments, :mollom_id
9
+ end
10
+ end
11
+
@@ -0,0 +1,22 @@
1
+ class MoveConfigToMigrations < ActiveRecord::Migration
2
+ def self.up
3
+ if Radiant::Config.table_exists?
4
+ { 'notification' => 'false',
5
+ 'notification_from' => '',
6
+ 'notification_to' => '',
7
+ 'notification_site_name' => '',
8
+ 'notify_creator' => 'true',
9
+ 'notify_updater' => 'false',
10
+ 'akismet_key' => '',
11
+ 'akismet_url' => '',
12
+ 'mollom_privatekey' => '',
13
+ 'mollom_publickey' => '',
14
+ 'filters_enabled' => 'true',
15
+ }.each{|k,v| Radiant::Config.create(:key => "comments.#{k}", :value => v) unless Radiant::Config["comments.#{k}"]}
16
+ end
17
+ end
18
+
19
+ def self.down
20
+ # not necessary
21
+ end
22
+ end