adva_comments 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/adva_comments.gemspec +20 -0
- data/app/assets/javascripts/adva_comments/jquery.comments.js +41 -0
- data/app/assets/stylesheets/adva_comments/admin/comments.scss +34 -0
- data/app/assets/stylesheets/adva_comments/comments.scss +50 -0
- data/app/controllers/admin/comments_controller.rb +86 -0
- data/app/controllers/comments_controller.rb +109 -0
- data/app/helpers/admin/comments_helper.rb +32 -0
- data/app/helpers/comments_helper.rb +71 -0
- data/app/mailers/comment_mailer.rb +8 -0
- data/app/models/comment.rb +94 -0
- data/app/views/admin/articles/_comments_settings.html.erb +1 -0
- data/app/views/admin/comments/_form.html.erb +12 -0
- data/app/views/admin/comments/edit.html.erb +9 -0
- data/app/views/admin/comments/index.html.erb +43 -0
- data/app/views/admin/sections/_comments_settings.html.erb +7 -0
- data/app/views/admin/sites/_comments_settings.html.erb +7 -0
- data/app/views/comment_mailer/comment_notification.html.erb +12 -0
- data/app/views/comments/_comment.html.erb +13 -0
- data/app/views/comments/_form.html.erb +44 -0
- data/app/views/comments/_list.html.erb +8 -0
- data/app/views/comments/comments.atom.builder +16 -0
- data/app/views/comments/preview.html.erb +3 -0
- data/app/views/comments/show.html.erb +12 -0
- data/config/initializers/article.rb +13 -0
- data/config/initializers/content.rb +17 -0
- data/config/initializers/controllers.rb +25 -0
- data/config/initializers/menus.rb +24 -0
- data/config/initializers/section.rb +15 -0
- data/config/initializers/site.rb +11 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20080401000007_create_comments_table.rb +22 -0
- data/db/migrate/20080721141112_add_comment_board_id.rb +9 -0
- data/lib/action_controller/acts_as_commentable.rb +43 -0
- data/lib/active_record/has_many_comments.rb +49 -0
- data/lib/adva_comments/version.rb +3 -0
- data/lib/adva_comments.rb +19 -0
- data/lib/format.rb +3 -0
- data/test/contexts.rb +29 -0
- data/test/functional/admin/comments_controller_test.rb +200 -0
- data/test/functional/comments_controller_test.rb +133 -0
- data/test/functional/comments_routes_test.rb +17 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/helpers/admin/comments_helper_test.rb +23 -0
- data/test/unit/helpers/comments_helper_test.rb +147 -0
- data/test/unit/models/comment_test.rb +150 -0
- data/test/unit/models/commentable_test.rb +30 -0
- data/test/unit/observers/activities_comment_observer_test.rb +45 -0
- metadata +132 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
<%= content_for :sidebar do %>
|
2
|
+
<!--
|
3
|
+
<div class="tabs">
|
4
|
+
<ul>
|
5
|
+
<li class="active"><a href="#filters" onclick="return false;"><%= t(:'adva.titles.filters') %></a></li>
|
6
|
+
</ul>
|
7
|
+
<div class="tab active" id="tab_filters">
|
8
|
+
<%= filter_for(Comment) %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
-->
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= will_paginate @comments %>
|
15
|
+
|
16
|
+
<ul id="comments_list">
|
17
|
+
<% if @comments.present? %>
|
18
|
+
<% @comments.each do |comment, i| %>
|
19
|
+
<li class="<%= cycle 'alt', '' %>" id="<%= dom_id(comment) %>">
|
20
|
+
<h4><%= link_to comment.commentable.title, [comment.commentable.section, comment.commentable] if comment.commentable %></h4>
|
21
|
+
<div class="actions">
|
22
|
+
<%= comment.approved? ?
|
23
|
+
link_to(t(:'adva.comments.links.unapprove'), admin_comment_path(comment, "comment[approved]" => 0, :return_to => request.fullpath), :class => 'text', :method => :put) :
|
24
|
+
link_to(t(:'adva.comments.links.approve'), admin_comment_path(comment, "comment[approved]" => 1, :return_to => request.fullpath), :class => 'text', :method => :put) %>
|
25
|
+
<%= link_to_edit(comment, :url => edit_admin_comment_path(comment, :return_to => request.fullpath)) %>
|
26
|
+
<%= link_to_delete(comment, :url => admin_comment_path(comment, :return_to => request.fullpath)) %>
|
27
|
+
</div>
|
28
|
+
<cite>
|
29
|
+
<%= link_to_author(comment) %>
|
30
|
+
<%= "(#{comment.author_email})" %>
|
31
|
+
<%= t(:'adva.comments.said_time_ago', :time => time_ago_in_words(comment.created_at)) %>
|
32
|
+
</cite>
|
33
|
+
<blockquote>
|
34
|
+
<%= strip_tags(comment.body) %>
|
35
|
+
</blockquote>
|
36
|
+
</li>
|
37
|
+
<% end %>
|
38
|
+
<% else %>
|
39
|
+
<li class="alt"><%= params[:filters] ? t(:'adva.comments.no_filtered_comments') : t(:'adva.comments.no_comments') %></li>
|
40
|
+
<% end %>
|
41
|
+
</ul>
|
42
|
+
|
43
|
+
<%= will_paginate @comments %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<p>Hello,</p>
|
2
|
+
|
3
|
+
<p>A new comment has been posted on <%= @comment.site.name %>. Please <%= link_to "log in", admin_comments_url(@comment.site, :host => @comment.site.host) %> and approve or delete it.</p>
|
4
|
+
|
5
|
+
<p>
|
6
|
+
Page: <%= @comment.commentable.title %><br />
|
7
|
+
Name: <%= @comment.author_name %><br />
|
8
|
+
Email: <%= @comment.author_email %><br />
|
9
|
+
Homepage: <%= @comment.author_homepage %><br />
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<p><%= @comment.body %></p>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<li id="<%= dom_id(comment) %>" class="<%= cycle 'alt', '' %> clearing">
|
2
|
+
<div class="meta">
|
3
|
+
<p><%= link_to_author(comment) %></p>
|
4
|
+
<p><%= datetime_with_microformat(comment.created_at, :format => :long) %></p>
|
5
|
+
<% unless comment.approved? %>
|
6
|
+
<p><%= t(:'adva.comments.info.under_review') %></p>
|
7
|
+
<% end %>
|
8
|
+
</div>
|
9
|
+
<div class="comment">
|
10
|
+
<%= comment.body_html %>
|
11
|
+
<a href="#<%= dom_id(comment) %>" title="" style="display:none;">#</a>
|
12
|
+
</div>
|
13
|
+
</li>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<%# @comment ||= commentable.comments.build %>
|
2
|
+
<% if @comment %>
|
3
|
+
<% authorized_tag(:div, :create, @comment, :id => 'comment_form_wrapper') do %>
|
4
|
+
<div id="registered_author" style="display: none;">
|
5
|
+
<p><%= t(:'adva.info.greeting_logged_in') %></p>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<h2><%= @comment.new_record? ? t(:'adva.comments.titles.add_reply') : t(:'adva.comments.titles.edit') %></h2>
|
9
|
+
|
10
|
+
<%= form_for :comment, @comment, :url => (@comment.new_record? ? comments_path : comment_path(@comment)), :html => { :id => 'comment_form', :method => (@comment.new_record? ? :post : :put) } do |f| -%>
|
11
|
+
<%= invisible_captcha :homepage, :comment %>
|
12
|
+
<%= comment_form_hidden_fields commentable %>
|
13
|
+
|
14
|
+
<%= fields_for @comment.author do |author| %>
|
15
|
+
<div id="anonymous_author">
|
16
|
+
<p>
|
17
|
+
<%= author.label :name, 'Name' %>
|
18
|
+
<%= author.text_field :name %>
|
19
|
+
</p>
|
20
|
+
<p>
|
21
|
+
<%= author.label :email, 'E-Mail' %>
|
22
|
+
<%= author.email_field :email %>
|
23
|
+
</p>
|
24
|
+
<p>
|
25
|
+
<%= author.label :homepage %>
|
26
|
+
<%= author.text_field :homepage %>
|
27
|
+
</p>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
|
31
|
+
<p>
|
32
|
+
<%= f.text_area :body %>
|
33
|
+
</p>
|
34
|
+
|
35
|
+
<p id="preview"></p>
|
36
|
+
|
37
|
+
<p>
|
38
|
+
<input type="text" name="comment[url]" style="background-color: transparent; border: 0px" />
|
39
|
+
<%= submit_tag (@comment.new_record? ? t(:'adva.comments.titles.submit_comment') : t(:'adva.comments.titles.save_comment')) %>
|
40
|
+
<%= link_to_remote_comment_preview %>
|
41
|
+
</p>
|
42
|
+
<% end %>
|
43
|
+
<% end %>
|
44
|
+
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
atom_feed :url => request.url do |feed|
|
2
|
+
feed.title comments_feed_title(@site, @section, @commentable)
|
3
|
+
feed.updated @comments.present? ? @comments.first.created_at : Time.now
|
4
|
+
|
5
|
+
@comments.each do |comment|
|
6
|
+
url = show_url(comment.commentable, :anchor => dom_id(comment))
|
7
|
+
feed.entry comment, :url => url do |entry|
|
8
|
+
entry.title I18n.t(:'adva.comments.titles.comment_on_by', :on => comment.commentable.title, :by => comment.author_name)
|
9
|
+
entry.content comment.body_html, :type => 'html'
|
10
|
+
entry.author do |author|
|
11
|
+
author.name comment.author_name
|
12
|
+
author.email comment.author_email
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div id="comments">
|
2
|
+
<h2><%= t(:'adva.comments.titles.comment_number', :number => @comment.id) %></h2>
|
3
|
+
<p>
|
4
|
+
<%= t(:'adva.comments.labels.on') %>: <%= link_to_content @comment.commentable %>
|
5
|
+
</p>
|
6
|
+
<ol>
|
7
|
+
<%= render :partial => 'comments/comment', :object => @comment %>
|
8
|
+
</ol>
|
9
|
+
</div>
|
10
|
+
<% if !@comment.approved? && current_user.admin? %>
|
11
|
+
<%= render :partial => 'comments/form', :locals => { :commentable => @comment.commentable } %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveSupport::Reloader.to_prepare do
|
2
|
+
Article.class_eval do
|
3
|
+
def accept_comments?
|
4
|
+
published? && (comment_age > -1) && (comment_age == 0 || comments_expired_at > Time.zone.now)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class ArticleFormBuilder < ExtensibleFormBuilder
|
10
|
+
after(:article, :filter) do |f|
|
11
|
+
render :partial => 'admin/articles/comments_settings', :locals => { :f => f }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveSupport::Reloader.to_prepare do
|
2
|
+
Content.class_eval do
|
3
|
+
# has_many_comments :polymorphic => true
|
4
|
+
has_many_comments :as => :commentable
|
5
|
+
|
6
|
+
delegate :comment_filter, :to => :site
|
7
|
+
delegate :accept_comments?, :to => :section
|
8
|
+
|
9
|
+
def comments_expired_at
|
10
|
+
if comment_age == -1
|
11
|
+
9999.years.from_now
|
12
|
+
else
|
13
|
+
(published_at || Time.zone.now) + comment_age.days
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
ActiveSupport::Reloader.to_prepare do
|
2
|
+
BaseController.class_eval do
|
3
|
+
helper :comments
|
4
|
+
|
5
|
+
def comments # FIXME why isn't this in acts_as_commentable ?
|
6
|
+
@comments = @commentable.approved_comments
|
7
|
+
respond_to do |format|
|
8
|
+
format.atom { render :template => 'comments/comments', :layout => false }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Admin::BaseController.helper :comments, :'admin/comments'
|
14
|
+
|
15
|
+
ArticlesController.class_eval do
|
16
|
+
acts_as_commentable
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def set_commentable
|
21
|
+
set_article if params[:permalink]
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Menus
|
2
|
+
module Admin
|
3
|
+
# will be concatenated onto existing sites menu via javascript
|
4
|
+
class Sites < Menu::Group
|
5
|
+
define do
|
6
|
+
namespace :admin
|
7
|
+
menu :left, :class => 'main' do
|
8
|
+
item :comments, :action => :index, :resource => :comment
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Comments < Menu::Group
|
14
|
+
define do
|
15
|
+
id :main
|
16
|
+
parent Sites.new.build(scope).find(:comments)
|
17
|
+
|
18
|
+
menu :left, :class => 'left' do
|
19
|
+
item :comments, :action => :index, :resource => :comment
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SectionFormBuilder < ExtensibleFormBuilder
|
2
|
+
before(:section, :submit_buttons) do |f|
|
3
|
+
unless @section.type == 'Forum'
|
4
|
+
render :partial => 'admin/sections/comments_settings', :locals => { :f => f }
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
ActiveSupport::Reloader.to_prepare do
|
9
|
+
Section.class_eval do
|
10
|
+
def accept_comments?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class SiteFormBuilder < ExtensibleFormBuilder
|
2
|
+
after(:site, :default_fields) do |f|
|
3
|
+
render :partial => 'admin/sites/comments_settings', :locals => { :f => f }
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
ActiveSupport::Reloader.to_prepare do
|
8
|
+
Site.class_eval do
|
9
|
+
has_many_comments
|
10
|
+
end
|
11
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateCommentsTable < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :comments, :force => true do |t|
|
4
|
+
t.references :site
|
5
|
+
t.references :section
|
6
|
+
# t.references :topic # TODO can we use the commentable reference as the topic reference?
|
7
|
+
t.references :commentable, :polymorphic => true
|
8
|
+
t.references :author, :polymorphic => true
|
9
|
+
t.string :author_name, :limit => 40
|
10
|
+
t.string :author_email, :limit => 40
|
11
|
+
t.string :author_homepage
|
12
|
+
t.text :body
|
13
|
+
t.text :body_html
|
14
|
+
t.integer :approved, :null => false, :default => 0
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :comments
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActionController
|
2
|
+
module ActsAsCommentable
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
extend ActMacro
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ActMacro
|
10
|
+
def acts_as_commentable(options = {})
|
11
|
+
return if acts_as_commentable?
|
12
|
+
include InstanceMethods
|
13
|
+
|
14
|
+
before_action :set_commentable, :only => :comments
|
15
|
+
before_action :set_comment, :except => :comments
|
16
|
+
helper :comments
|
17
|
+
end
|
18
|
+
|
19
|
+
def acts_as_commentable?
|
20
|
+
included_modules.include?(ActionController::ActsAsCommentable::InstanceMethods)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
def comments
|
26
|
+
@comments = @commentable.approved_comments
|
27
|
+
respond_to do |format|
|
28
|
+
format.atom do
|
29
|
+
render :template => 'comments/comments', :layout => false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def set_comment
|
37
|
+
@comment = Comment.new params[:comment]
|
38
|
+
@comment.author = User.anonymous
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module HasManyComments
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ActMacro
|
5
|
+
end
|
6
|
+
|
7
|
+
module ActMacro
|
8
|
+
def has_many_comments(options = {})
|
9
|
+
return if has_many_comments?
|
10
|
+
|
11
|
+
order_options = options.delete(:order) || [:created_at, :id]
|
12
|
+
options[:class_name] ||= 'Comment'
|
13
|
+
|
14
|
+
has_counter :comments,
|
15
|
+
:as => options[:as]
|
16
|
+
|
17
|
+
has_counter :approved_comments,
|
18
|
+
:as => options[:as],
|
19
|
+
:class_name => 'Comment',
|
20
|
+
:callbacks => {
|
21
|
+
:after_approve => :increment!,
|
22
|
+
:after_unapprove => :decrement!,
|
23
|
+
:after_destroy => lambda { |record| :decrement! if record.approved? }
|
24
|
+
}
|
25
|
+
|
26
|
+
options.delete(:as) unless options[:as] == :commentable
|
27
|
+
with_options options do |c|
|
28
|
+
c.has_many :comments, -> { order(order_options) }, dependent: :delete_all do
|
29
|
+
def by_author(author)
|
30
|
+
find_all_by_author_id_and_author_type(author.id, author.class.name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
c.has_many :approved_comments, -> { where(["comments.approved = ?", 1]).order(order_options) }
|
34
|
+
c.has_many :unapproved_comments, -> { where(["comments.approved = ?", 0]).order(order_options) }
|
35
|
+
end
|
36
|
+
|
37
|
+
include InstanceMethods
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_many_comments?
|
41
|
+
included_modules.include? ActiveRecord::HasManyComments::InstanceMethods
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceMethods
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
ActiveRecord::Base.send :include, ActiveRecord::HasManyComments
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# require "adva_comments/version"
|
2
|
+
require "rails"
|
3
|
+
|
4
|
+
require "active_record/has_many_comments"
|
5
|
+
require "action_controller/acts_as_commentable"
|
6
|
+
require "invisible_captcha"
|
7
|
+
|
8
|
+
module AdvaComments
|
9
|
+
class Engine < Rails::Engine
|
10
|
+
initializer "add assets to precompilation list" do |app|
|
11
|
+
app.config.assets.precompile += %w(adva_comments/admin/comments.css)
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer "adva_comments.init" do
|
15
|
+
ActiveRecord::Base.send :include, ActiveRecord::HasManyComments
|
16
|
+
ActionController::Base.send :include, ActionController::ActsAsCommentable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/format.rb
ADDED
data/test/contexts.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
class Test::Unit::TestCase
|
2
|
+
share :valid_comment_params do
|
3
|
+
before do
|
4
|
+
@params = { :comment => { :commentable_id => @article.id,
|
5
|
+
:commentable_type => 'Article',
|
6
|
+
:body => 'the comment body' } }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
share :invalid_comment_params do
|
11
|
+
before do
|
12
|
+
@params = { :comment => { :commentable_id => @article.id,
|
13
|
+
:commentable_type => 'Article',
|
14
|
+
:body => nil } }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
share :an_approved_comment do
|
19
|
+
before do
|
20
|
+
@comment = @section.approved_comments.first
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
share :an_unapproved_comment do
|
25
|
+
before do
|
26
|
+
@comment = @section.unapproved_comments.first
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|