radiant-comments-extension 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CHANGELOG +40 -0
- data/HELP_admin.markdown +52 -0
- data/HELP_designer.markdown +36 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +53 -0
- data/Rakefile +133 -0
- data/TODO +6 -0
- data/VERSION +1 -0
- data/app/controllers/admin/comments_controller.rb +130 -0
- data/app/controllers/comments_controller.rb +59 -0
- data/app/helpers/admin/comments_helper.rb +7 -0
- data/app/models/akismet_spam_filter.rb +37 -0
- data/app/models/comment.rb +121 -0
- data/app/models/comment_mailer.rb +24 -0
- data/app/models/mollom_spam_filter.rb +52 -0
- data/app/models/simple_spam_filter.rb +38 -0
- data/app/models/spam_filter.rb +43 -0
- data/app/views/admin/comments/_comment.rhtml +34 -0
- data/app/views/admin/comments/_form.rhtml +36 -0
- data/app/views/admin/comments/edit.rhtml +5 -0
- data/app/views/admin/comments/index.rhtml +55 -0
- data/app/views/admin/pages/_comments.rhtml +0 -0
- data/app/views/admin/pages/_edit_comments_enabled.rhtml +8 -0
- data/app/views/admin/pages/_index_head_view_comments.rhtml +1 -0
- data/app/views/admin/pages/_index_view_comments.rhtml +11 -0
- data/app/views/comment_mailer/comment_notification.rhtml +21 -0
- data/app/views/comments/_comment.rhtml +1 -0
- data/app/views/comments/_form.rhtml +23 -0
- data/app/views/comments/_new.rhtml +5 -0
- data/autotest/discover.rb +3 -0
- data/comments_extension.rb +81 -0
- data/cucumber.yml +1 -0
- data/db/migrate/001_create_comments.rb +29 -0
- data/db/migrate/002_create_snippets.rb +115 -0
- data/db/migrate/003_change_filter_id_from_integer_to_string.rb +10 -0
- data/db/migrate/004_add_approval_columns.rb +13 -0
- data/db/migrate/005_add_mollomid_column.rb +11 -0
- data/db/migrate/006_move_config_to_migrations.rb +22 -0
- data/db/migrate/007_add_preference_for_simple_spamcheck.rb +12 -0
- data/features/support/env.rb +16 -0
- data/features/support/paths.rb +16 -0
- data/lib/akismet.rb +134 -0
- data/lib/comment_page_extensions.rb +41 -0
- data/lib/comment_tags.rb +338 -0
- data/lib/mollom.rb +246 -0
- data/lib/radiant-comments-extension.rb +0 -0
- data/lib/tasks/comments_extension_tasks.rake +68 -0
- data/public/images/admin/accept.png +0 -0
- data/public/images/admin/comment_edit.png +0 -0
- data/public/images/admin/comments.png +0 -0
- data/public/images/admin/comments_delete.png +0 -0
- data/public/images/admin/delete.png +0 -0
- data/public/images/admin/email.png +0 -0
- data/public/images/admin/error.png +0 -0
- data/public/images/admin/link.png +0 -0
- data/public/images/admin/page_white_edit.png +0 -0
- data/public/images/admin/table_save.png +0 -0
- data/public/images/admin/tick.png +0 -0
- data/public/stylesheets/admin/comments.css +41 -0
- data/radiant-comments-extension.gemspec +133 -0
- data/spec/controllers/admin/comments_controller_spec.rb +57 -0
- data/spec/controllers/admin/comments_routing_spec.rb +43 -0
- data/spec/controllers/page_postback_spec.rb +51 -0
- data/spec/datasets/comments_dataset.rb +7 -0
- data/spec/models/akismet_spam_filter_spec.rb +61 -0
- data/spec/models/comment_spec.rb +148 -0
- data/spec/models/comment_tags_spec.rb +55 -0
- data/spec/models/mollom_spam_filter_spec.rb +103 -0
- data/spec/models/simple_spam_filter_spec.rb +44 -0
- data/spec/models/spam_filter_spec.rb +38 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- data/test/fixtures/users.yml +6 -0
- data/test/integration/comment_enabling_test.rb +18 -0
- data/test/test_helper.rb +24 -0
- data/test/unit/comment_test.rb +52 -0
- metadata +177 -0
@@ -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} — 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,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,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,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
|