adva_comments 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/adva_comments.gemspec +20 -0
  8. data/app/assets/javascripts/adva_comments/jquery.comments.js +41 -0
  9. data/app/assets/stylesheets/adva_comments/admin/comments.scss +34 -0
  10. data/app/assets/stylesheets/adva_comments/comments.scss +50 -0
  11. data/app/controllers/admin/comments_controller.rb +86 -0
  12. data/app/controllers/comments_controller.rb +109 -0
  13. data/app/helpers/admin/comments_helper.rb +32 -0
  14. data/app/helpers/comments_helper.rb +71 -0
  15. data/app/mailers/comment_mailer.rb +8 -0
  16. data/app/models/comment.rb +94 -0
  17. data/app/views/admin/articles/_comments_settings.html.erb +1 -0
  18. data/app/views/admin/comments/_form.html.erb +12 -0
  19. data/app/views/admin/comments/edit.html.erb +9 -0
  20. data/app/views/admin/comments/index.html.erb +43 -0
  21. data/app/views/admin/sections/_comments_settings.html.erb +7 -0
  22. data/app/views/admin/sites/_comments_settings.html.erb +7 -0
  23. data/app/views/comment_mailer/comment_notification.html.erb +12 -0
  24. data/app/views/comments/_comment.html.erb +13 -0
  25. data/app/views/comments/_form.html.erb +44 -0
  26. data/app/views/comments/_list.html.erb +8 -0
  27. data/app/views/comments/comments.atom.builder +16 -0
  28. data/app/views/comments/preview.html.erb +3 -0
  29. data/app/views/comments/show.html.erb +12 -0
  30. data/config/initializers/article.rb +13 -0
  31. data/config/initializers/content.rb +17 -0
  32. data/config/initializers/controllers.rb +25 -0
  33. data/config/initializers/menus.rb +24 -0
  34. data/config/initializers/section.rb +15 -0
  35. data/config/initializers/site.rb +11 -0
  36. data/config/routes.rb +9 -0
  37. data/db/migrate/20080401000007_create_comments_table.rb +22 -0
  38. data/db/migrate/20080721141112_add_comment_board_id.rb +9 -0
  39. data/lib/action_controller/acts_as_commentable.rb +43 -0
  40. data/lib/active_record/has_many_comments.rb +49 -0
  41. data/lib/adva_comments/version.rb +3 -0
  42. data/lib/adva_comments.rb +19 -0
  43. data/lib/format.rb +3 -0
  44. data/test/contexts.rb +29 -0
  45. data/test/functional/admin/comments_controller_test.rb +200 -0
  46. data/test/functional/comments_controller_test.rb +133 -0
  47. data/test/functional/comments_routes_test.rb +17 -0
  48. data/test/test_helper.rb +4 -0
  49. data/test/unit/helpers/admin/comments_helper_test.rb +23 -0
  50. data/test/unit/helpers/comments_helper_test.rb +147 -0
  51. data/test/unit/models/comment_test.rb +150 -0
  52. data/test/unit/models/commentable_test.rb +30 -0
  53. data/test/unit/observers/activities_comment_observer_test.rb +45 -0
  54. metadata +132 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e97b4790dbbafc5bd5a7b1587994a0376996f0afbfaa066105f48be741a60c39
4
+ data.tar.gz: 7c89022fc00fd8ce186d011b2d7b0e732094613e7d2f410f9be8f01e6a8b0fa0
5
+ SHA512:
6
+ metadata.gz: b791d5fa817b56fe2ffd25ea6fbfcb150ec3e89506b17199e2234895442d36d134be438897878b915982e77631d995a0b6409b7e395f601fca0ee866a7e5ebc2
7
+ data.tar.gz: 0a5b0ad8cd654fc989e41d19616ffa513502132272238eb81b9a5eca98aa76074d51f88abc73ba6d0ac4e1f32921b153f3a90530294c86933615ae931fdcd92e
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in adva_comments.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Micah Geisel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # AdvaComments
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'adva_comments'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install adva_comments
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/adva_comments/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Micah Geisel"]
6
+ gem.email = ["micah@botandrose.com"]
7
+ gem.description = %q{Adva Comments}
8
+ gem.summary = %q{Engine for Adva CMS commenting component}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "adva_comments"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = AdvaComments::VERSION
17
+
18
+ gem.add_dependency "validates_email_format_of"
19
+ gem.add_dependency "invisible_captcha"
20
+ end
@@ -0,0 +1,41 @@
1
+ var CommentForm = {
2
+ init: function() {
3
+ var user_name = Cookie.get('uname');
4
+ if (user_name) {
5
+ user_name = unescape(user_name).replace(/\+/g, " ");
6
+ try { $('#registered_author span').each(function() { $(this).html(user_name); }); } catch(err) {}
7
+ try { $('#registered_author').show(); } catch(err) {}
8
+ try { $('#anonymous_author').hide(); } catch(err) {}
9
+ }
10
+ }
11
+ };
12
+
13
+ var Comment = {
14
+ preview: function(event) {
15
+ event.preventDefault();
16
+ $.ajax({
17
+ url: this.href,
18
+ type: 'post',
19
+ dataType: 'html',
20
+ data: $('form#comment_form').serializeArray(),
21
+ success: function(data, status) {
22
+ $('#preview').html(data);
23
+ },
24
+ beforeSend: function(xhr) {
25
+ $('#comment_preview_spinner').show();
26
+ },
27
+ complete: function(xhr, status) {
28
+ $('#comment_preview_spinner').hide();
29
+ }
30
+ });
31
+ }
32
+ }
33
+
34
+ $(document).ready(function() {
35
+ if($('#anonymous_author')) {
36
+ CommentForm.init();
37
+ }
38
+
39
+ $('a#preview_comment').show();
40
+ $('a#preview_comment').click(Comment.preview);
41
+ });
@@ -0,0 +1,34 @@
1
+ #comments_list {
2
+ list-style-type: none;
3
+ margin: 0;
4
+ padding: 0;
5
+ }
6
+ #comments_list li {
7
+ margin-top: 15px;
8
+ padding: 0 40px 0 25px;
9
+ background: image_url("adva_cms/icons/comment.png") no-repeat left 3px;
10
+ }
11
+ #comments_list li.highlight {
12
+ padding: 20px 20px 20px 55px !important;
13
+ padding-bottom: 3px;
14
+ border: 1px solid #add;
15
+ background-color: #eaf6f6 !important;
16
+ margin: 20px 0;
17
+ }
18
+ #comments_list .actions {
19
+ float: right;
20
+ margin-top: -1px;
21
+ height: 20px;
22
+ line-height: 20px;
23
+ overflow: hidden;
24
+ }
25
+ #comments_list .actions a {
26
+ margin-top: -2px;
27
+ }
28
+ #comments_list blockquote {
29
+ margin: 0;
30
+ }
31
+ #comments_list cite {
32
+ font-size: 12px;
33
+ font-style: normal;
34
+ }
@@ -0,0 +1,50 @@
1
+ /* COMMENTS */
2
+
3
+ #comments {
4
+ padding-bottom: 9px;
5
+ }
6
+ #comments h3 {
7
+ font-size: 18px;
8
+ line-height: 18px;
9
+ margin: 18px 0 18px 0;
10
+ }
11
+ #comments ol {
12
+ list-style-type: none;
13
+ margin-left: 0;
14
+ }
15
+ #comments ol li {
16
+ padding-bottom: 17px;
17
+ margin-bottom: 18px;
18
+ border-bottom: 1px solid #bbb;
19
+ }
20
+ #comments .meta p {
21
+ margin: 0;
22
+ }
23
+ #comments .comment {
24
+ padding-left: 220px;
25
+ }
26
+
27
+ /* COMMENTS FORM */
28
+
29
+ #comment_form_wrapper {
30
+ padding-left: 220px;
31
+ padding-bottom: 9px;
32
+ margin-bottom: 26px;
33
+ border-bottom: 1px solid #bbb;
34
+ }
35
+ #comment_user {
36
+ float: right;
37
+ margin-top: 3px;
38
+ }
39
+ #comment_form label {
40
+ display: block;
41
+ float: left;
42
+ width: 100px;
43
+ }
44
+ #comment_form input {
45
+ width: 180px;
46
+ }
47
+ #comment_form textarea {
48
+ height: 150px;
49
+ width: 99%;
50
+ }
@@ -0,0 +1,86 @@
1
+ class Admin::CommentsController < Admin::BaseController
2
+ layout "admin"
3
+
4
+ before_action :set_comment, :only => [:edit, :update, :destroy]
5
+ before_action :set_commentable, :set_comment_params, :only => :create
6
+ after_action :postback_spaminess, :only => [:update]
7
+
8
+ def index
9
+ # FIXME how to remove the Topic dependency here?
10
+ # maybe make Comment a subclass of Comment::Base or something so that we can use STI to exclude
11
+ # special comment types?
12
+ @comments = @site.comments.where(['commentable_type NOT IN (?)', 'Topic']).
13
+ reorder("comments.created_at DESC").
14
+ paginate(:page => current_page, :per_page => 25)
15
+ end
16
+
17
+ def edit
18
+ end
19
+
20
+ def update
21
+ if @comment.update params[:comment]
22
+ trigger_events @comment
23
+ flash[:notice] = t(:'adva.comments.flash.update.success')
24
+ redirect_to params[:return_to] || admin_comments_url
25
+ else
26
+ flash.now[:error] = t(:'adva.comments.flash.update.failure')
27
+ render :action => :edit
28
+ end
29
+ end
30
+
31
+ def destroy
32
+ @comment.destroy
33
+ trigger_events @comment
34
+ flash[:notice] = t(:'adva.comments.flash.destroy.success')
35
+ redirect_to params[:return_to] || admin_comments_url
36
+ end
37
+
38
+ private
39
+
40
+ def set_menu
41
+ @menu = Menus::Admin::Comments.new
42
+ end
43
+
44
+ def set_commentable
45
+ type, id = params[:comment].values_at(:commentable_type, :commentable_id)
46
+ @commentable = type.constantize.find id
47
+ end
48
+
49
+ def set_comment_params
50
+ params[:comment].merge! :site_id => @commentable.site_id,
51
+ :section_id => @commentable.section_id,
52
+ :author => current_user
53
+ end
54
+
55
+ def set_comment
56
+ @comment = Comment.find(params[:id])
57
+ end
58
+
59
+ def filter_options options
60
+ case params[:filter]
61
+ when 'state'
62
+ params[:state] == 'approved' ? options[:conditions] = "approved = '1'" : options[:conditions] = "approved = '0'"
63
+ when 'body'
64
+ options[:conditions] = Comment.send(:sanitize_sql, ["LOWER(body) LIKE :query", {:query => "%#{params[:query].downcase}%"}])
65
+ when 'author_name'
66
+ options[:conditions] = Comment.send(:sanitize_sql, ["LOWER(author_name) LIKE :query", {:query => "%#{params[:query].downcase}%"}])
67
+ when 'author_email'
68
+ options[:conditions] = Comment.send(:sanitize_sql, ["LOWER(author_email) LIKE :query", {:query => "%#{params[:query].downcase}%"}])
69
+ when 'author_homepage'
70
+ options[:conditions] = Comment.send(:sanitize_sql, ["LOWER(author_homepage) LIKE :query", {:query => "%#{params[:query].downcase}%"}])
71
+ end
72
+ options
73
+ end
74
+
75
+ def postback_spaminess
76
+ if @comment.approved_changed? and @site.respond_to?(:spam_engine)
77
+ spaminess = @comment.approved? ? :ham : :spam
78
+ @site.spam_engine.mark_spaminess(spaminess, @comment, :url => show_url(@comment.commentable))
79
+ end
80
+ end
81
+
82
+ def current_resource
83
+ @comment ? @comment.commentable : @content || @section || @site
84
+ end
85
+ end
86
+
@@ -0,0 +1,109 @@
1
+ class CommentsController < BaseController
2
+ # TODO apparently it is not possible to use protect_from_forgery with
3
+ # page cached forms? is that correct? as protect_from_forgery seems to
4
+ # validate the form token against the session and ideally when all pages
5
+ # and assets are cached there is no session at all this seems to make sense.
6
+ #
7
+ # Rails docs say: "done by embedding a token based on the session ... in all
8
+ # forms and Ajax requests generated by Rails and then verifying the authenticity
9
+ # of that token in the controller"
10
+ # http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html
11
+ #
12
+ # Note: Could fetch forgery token via AJAX?
13
+
14
+ protect_from_forgery :except => [:preview, :create]
15
+
16
+ authenticates_anonymous_user
17
+ layout 'default'
18
+
19
+ before_action :set_section
20
+ before_action :set_comment, :only => [:show, :update, :destroy]
21
+ before_action :set_commentable, :only => [:show, :preview, :create]
22
+
23
+ invisible_captcha only: [:create, :update], honeypot: :subtitle, if: -> { current_user.anonymous? }
24
+
25
+ def show
26
+ end
27
+
28
+ def preview
29
+ @comment = @commentable.comments.build(comment_params)
30
+ @comment.send(:process_filters)
31
+ render :layout => false
32
+ end
33
+
34
+ def create
35
+ @comment = @commentable.comments.build(comment_params)
36
+ if @comment.save
37
+ trigger_events @comment
38
+ CommentMailer.comment_notification(@comment).deliver_later
39
+ if current_user.anonymous?
40
+ flash.notice = "Your comment is being reviewed, and will be posted shortly. Thank you for commenting!"
41
+ else
42
+ @comment.update_column :approved, true
43
+ flash.notice = "You're an admin, so your comment is being posted immediately! Refresh the page to see it."
44
+ end
45
+ respond_to do |format|
46
+ format.html { redirect_to "#{request.env['HTTP_REFERER']}#comments" }
47
+ format.js { render json: true }
48
+ end
49
+ else
50
+ flash[:error] = @comment.errors.full_messages.to_sentence # TODO hu.
51
+ respond_to do |format|
52
+ format.html { redirect_to "#{request.env['HTTP_REFERER']}#comments" }
53
+ format.js { render json: false }
54
+ end
55
+ end
56
+ end
57
+
58
+ def update
59
+ if @comment.update(comment_params)
60
+ trigger_events(@comment)
61
+ flash.notice = t(:'adva.comments.flash.update.success')
62
+ render json: true
63
+ else
64
+ set_commentable
65
+ flash[:error] = @comment.errors.full_messages.to_sentence
66
+ render json: false
67
+ end
68
+ end
69
+
70
+ def destroy
71
+ @comment.destroy
72
+ trigger_events @comment
73
+ redirect_to "/", notice: t(:'adva.comments.flash.destroy.success')
74
+ end
75
+
76
+ protected
77
+
78
+ def comment_params
79
+ params.require(:comment).permit(
80
+ :author_email,
81
+ :author_name,
82
+ :body,
83
+ :commentable_id,
84
+ :commentable_type,
85
+ ).merge(site_id: @commentable.site_id, section_id: @commentable.section_id)
86
+ end
87
+
88
+ def set_comment
89
+ @comment = Comment.find(params[:id])
90
+ end
91
+
92
+ def set_commentable
93
+ @commentable = if @comment
94
+ @comment.commentable or raise ActiveRecord::RecordNotFound
95
+ else
96
+ begin
97
+ klass = params.dig(:comment, :commentable_type).constantize
98
+ raise NameError unless klass.has_many_comments?
99
+ rescue NameError
100
+ raise ActiveRecord::RecordNotFound
101
+ end
102
+ klass.find(params.dig(:comment, :commentable_id))
103
+ end
104
+ end
105
+
106
+ def current_resource
107
+ @comment || @commentable
108
+ end
109
+ end
@@ -0,0 +1,32 @@
1
+ module Admin
2
+ module CommentsHelper
3
+ def comment_expiration_options
4
+ I18n.with_options :scope => :'adva.comments.options.expiration' do |i18n|
5
+ [ [i18n.t(:not_allowed), -1 ],
6
+ [i18n.t(:never_expire), 0 ],
7
+ [i18n.t(:x_hours_after_publishing, :count => 24), 1 ],
8
+ [i18n.t(:x_weeks_after_publishing, :count => 1), 7 ],
9
+ [i18n.t(:x_months_after_publishing, :count => 1), 30],
10
+ [i18n.t(:x_months_after_publishing, :count => 3), 90] ]
11
+ end
12
+ end
13
+
14
+ def comments_filter_options
15
+ options = I18n.t(:'adva.comments.filter.options')
16
+
17
+ [[options[:all], 'all'],
18
+ [options[:state], 'state'],
19
+ [options[:body], 'body'],
20
+ [options[:author_name], 'author_name'],
21
+ [options[:author_email], 'author_email'],
22
+ [options[:author_url], 'author_homepage']]
23
+ end
24
+
25
+ def comments_state_options
26
+ options = I18n.t(:'adva.comments.state.options')
27
+
28
+ [[options[:approved], 'approved'],
29
+ [options[:unapproved], 'unapproved']]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ module CommentsHelper
2
+ def comments_feed_title(*owners)
3
+ options = owners.extract_options!
4
+ separator = options[:separator] || ' &raquo; '
5
+ I18n.t(:'adva.titles.comments') + ': ' + owners.compact.uniq.map(&:title).join(separator)
6
+ end
7
+
8
+ methods = %w(admin_comments_path admin_comment_path
9
+ new_admin_comment_path edit_admin_comment_path)
10
+
11
+ methods.each do |method|
12
+ module_eval <<-CODE, __FILE__, __LINE__
13
+ def #{method}(*args)
14
+ options = args.extract_options!
15
+ merge_admin_comments_query_params(options)
16
+ super *(args << options).compact
17
+ end
18
+ CODE
19
+ end
20
+
21
+ def link_to_content_comments_count(content, options = {:total => true})
22
+ total = content.comments_count
23
+ approved = content.approved_comments_count
24
+ return options[:alt] || t(:'adva.common.none') if approved == 0
25
+ text = if total == approved or !options[:total]
26
+ "#{approved.to_s.rjust(2, '0')}"
27
+ else
28
+ "#{approved.to_s.rjust(2, '0')} (#{total.to_s.rjust(2, '0')})"
29
+ end
30
+ link_to_content_comments(text, content)
31
+ end
32
+
33
+ def link_to_content_comments(*args)
34
+ options = args.extract_options!
35
+ text = args.shift if args.first.is_a?(String) || args.first.is_a?(Symbol)
36
+ content, comment = *args
37
+ return unless content.approved_comments_count > 0 || content.accept_comments?
38
+
39
+ text = t(text) if text.is_a?(Symbol)
40
+ text ||= t(:'adva.comments.titles.comment_with_count', :count => content.approved_comments_count)
41
+ options.merge! :anchor => (comment ? dom_id(comment) : 'comments')
42
+ link_to text, [content.section, content], options
43
+ end
44
+
45
+ def link_to_content_comment(*args)
46
+ options = args.extract_options!
47
+ args.insert(args.size - 1, args.last.commentable)
48
+ link_to_content_comments(*args << options)
49
+ end
50
+
51
+ def link_to_remote_comment_preview
52
+ link_to(I18n.t(:'adva.titles.preview'), preview_comments_path, :id => 'preview_comment', :style => "display:none;") +
53
+ image_tag('adva_cms/indicator.gif', :alt => '', :id => 'comment_preview_spinner', :style => 'display:none;')
54
+ end
55
+
56
+ def comment_form_hidden_fields(commentable)
57
+ hidden_field_tag('return_to', request.fullpath) + "\n" +
58
+ hidden_field_tag('comment[commentable_type]', commentable.class.name, :id => 'comment_commentable_type') + "\n" +
59
+ hidden_field_tag('comment[commentable_id]', commentable.id, :id => 'comment_commentable_id') + "\n"
60
+ end
61
+
62
+ private
63
+
64
+ # TODO obviously doesn't work as expected on the SectionsController where the
65
+ # section_id is in params[:id]
66
+ def merge_admin_comments_query_params(options)
67
+ options.merge! params.slice(:section_id, :content_id).reject{|key, value| value.blank? }.to_unsafe_hash
68
+ options.symbolize_keys!
69
+ options.delete(:section_id) if options[:content_id]
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ class CommentMailer < ActionMailer::Base
2
+ default :content_type => "text/html"
3
+
4
+ def comment_notification comment
5
+ @comment = comment
6
+ mail :to => comment.site.email, :from => comment.site.email, :subject => "#{comment.site.name}: New pending comment"
7
+ end
8
+ end
@@ -0,0 +1,94 @@
1
+ class Comment < ActiveRecord::Base
2
+ class CommentNotAllowed < StandardError; end
3
+
4
+ def self.approved
5
+ where :approved => true
6
+ end
7
+
8
+ def self.unapproved
9
+ where :approved => false
10
+ end
11
+
12
+ define_model_callbacks :approve, :unapprove
13
+
14
+ def around_save
15
+ if just_approved?
16
+ run_callbacks(:approve) { yield }
17
+ elsif just_unapproved?
18
+ run_callbacks(:unapprove) { yield }
19
+ else
20
+ yield
21
+ end
22
+ end
23
+
24
+ after_save do
25
+ commentable.touch
26
+ end
27
+
28
+ filtered_column :body
29
+ filters_attributes :sanitize => :body_html
30
+
31
+ has_filter :text => { :attributes => [:body] },
32
+ :state => { :states => [:approved, :unapproved] }
33
+
34
+ belongs_to :site
35
+ belongs_to :section
36
+ belongs_to :commentable, :polymorphic => true
37
+ # make sure we're storing the base clase for STI
38
+ def commentable_type=(sType)
39
+ super(sType.to_s.classify.constantize.base_class.to_s)
40
+ end
41
+ has_many :activities, :as => :object
42
+
43
+ composed_of :author, :class_name => "User", :mapping => [ %w(author_name name), %w(author_email email) ]
44
+
45
+ validates_presence_of :body, :commentable, :author_name, :author_email
46
+ validates_email_format_of :author_email
47
+
48
+ before_validation :set_owners
49
+ before_create :authorize_commenting
50
+
51
+ def owner
52
+ commentable
53
+ end
54
+
55
+ def filter
56
+ commentable.comment_filter
57
+ end
58
+
59
+ def unapproved?
60
+ !approved?
61
+ end
62
+
63
+ def just_approved?
64
+ approved_changed? and approved?
65
+ end
66
+
67
+ def just_unapproved?
68
+ approved_changed? and unapproved?
69
+ end
70
+
71
+ def state_changes
72
+ state_changes = if just_approved?
73
+ [:approved]
74
+ elsif just_unapproved?
75
+ [:unapproved]
76
+ end || []
77
+ super + state_changes
78
+ end
79
+
80
+ protected
81
+
82
+ def authorize_commenting
83
+ if commentable && !commentable.accept_comments?
84
+ raise CommentNotAllowed, I18n.t(:'adva.comments.messages.not_allowed')
85
+ end
86
+ end
87
+
88
+ def set_owners
89
+ if commentable # TODO in what cases would commentable be nil here?
90
+ self.site = commentable.site
91
+ self.section = commentable.section
92
+ end
93
+ end
94
+ end
@@ -0,0 +1 @@
1
+ <%= f.select(:comment_age, comment_expiration_options, {}, :label => :'adva.titles.comments') %>
@@ -0,0 +1,12 @@
1
+ <%= hidden_field_tag "return_to", params[:return_to] || request.request_uri %>
2
+
3
+ <% f.field_set do %>
4
+ <%= f.text_area :body, :rows => 8, :label => :'adva.titles.comment' %>
5
+ <% end %>
6
+
7
+ <%= yield if block_given? %>
8
+
9
+ <% f.buttons do %>
10
+ <%= submit_tag t(:'adva.common.save') %>
11
+ <%= link_to t(:'adva.common.cancel'), params[:return_to] if params[:return_to] %>
12
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <h3><%= t(:'adva.comments.titles.edit') %></h3>
2
+
3
+ <%= form_for [:admin, @comment] do |f| -%>
4
+ <% render :layout => 'form', :locals => {:f => f} do %>
5
+ <p>
6
+ <label><%= f.check_box :approved, {}, 1 %><%= t(:'adva.comments.labels.approved') %></label>
7
+ </p>
8
+ <% end -%>
9
+ <% end -%>