commontator 0.5.14 → 1.0.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.
Files changed (83) hide show
  1. data/README.md +47 -10
  2. data/Rakefile +6 -5
  3. data/app/controllers/commontator/application_controller.rb +3 -1
  4. data/app/controllers/commontator/application_controller.rb~ +5 -2
  5. data/app/controllers/commontator/comments_controller.rb +9 -10
  6. data/app/controllers/commontator/comments_controller.rb~ +9 -10
  7. data/app/controllers/commontator/commontator_controller.rb~ +22 -0
  8. data/app/controllers/commontator/subscriptions_controller.rb +2 -2
  9. data/app/controllers/commontator/subscriptions_controller.rb~ +3 -3
  10. data/app/controllers/commontator/threads_controller.rb +4 -3
  11. data/app/controllers/commontator/threads_controller.rb~ +5 -3
  12. data/app/helpers/commontator/commontator_helper.rb~ +7 -0
  13. data/app/mailers/commontator/subscriptions_mailer.rb +2 -1
  14. data/app/mailers/commontator/subscriptions_mailer.rb~ +3 -1
  15. data/app/models/commontator/comment.rb +13 -9
  16. data/app/models/commontator/comment.rb~ +14 -10
  17. data/app/models/commontator/subscription.rb +3 -3
  18. data/app/models/commontator/subscription.rb~ +19 -0
  19. data/app/models/commontator/thread.rb +17 -41
  20. data/app/models/commontator/thread.rb~ +119 -0
  21. data/app/views/commontator/shared/_thread.html.erb +4 -1
  22. data/app/views/commontator/shared/_thread.html.erb~ +5 -2
  23. data/app/views/commontator/subscriptions_mailer/comment_created_email.html.erb +1 -1
  24. data/app/views/commontator/subscriptions_mailer/comment_created_email.html.erb~ +6 -0
  25. data/config/initializers/commontator.rb +42 -64
  26. data/{test/dummy/config/initializers/commontator.rb → config/initializers/commontator.rb~} +42 -64
  27. data/db/migrate/0_install_commontator.rb +1 -1
  28. data/{test/dummy/db/migrate/1_install_commontator.commontator.rb → db/migrate/0_install_commontator.rb~} +1 -2
  29. data/lib/commontator.rb +7 -12
  30. data/lib/commontator.rb~ +7 -12
  31. data/lib/commontator/commontable_config.rb +1 -1
  32. data/lib/commontator/commontable_config.rb~ +13 -0
  33. data/lib/commontator/commontator_config.rb +1 -1
  34. data/lib/commontator/commontator_config.rb~ +13 -0
  35. data/lib/commontator/controller_includes.rb +1 -0
  36. data/lib/commontator/controller_includes.rb~ +1 -1
  37. data/lib/commontator/security_transgression.rb +3 -0
  38. data/{test/dummy/public/favicon.ico → lib/commontator/security_transgression.rb~} +0 -0
  39. data/lib/commontator/shared_helper.rb +1 -1
  40. data/lib/commontator/shared_helper.rb~ +2 -2
  41. data/lib/commontator/version.rb +1 -1
  42. data/lib/commontator/version.rb~ +1 -1
  43. metadata +46 -89
  44. data/test/commontator_test.rb +0 -7
  45. data/test/dummy/README.rdoc +0 -261
  46. data/test/dummy/Rakefile +0 -7
  47. data/test/dummy/app/assets/javascripts/application.js +0 -15
  48. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  49. data/test/dummy/app/controllers/application_controller.rb +0 -3
  50. data/test/dummy/app/helpers/application_helper.rb +0 -2
  51. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  52. data/test/dummy/config.ru +0 -4
  53. data/test/dummy/config/application.rb +0 -59
  54. data/test/dummy/config/boot.rb +0 -10
  55. data/test/dummy/config/database.yml +0 -25
  56. data/test/dummy/config/environment.rb +0 -5
  57. data/test/dummy/config/environments/development.rb +0 -37
  58. data/test/dummy/config/environments/production.rb +0 -67
  59. data/test/dummy/config/environments/test.rb +0 -37
  60. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  61. data/test/dummy/config/initializers/inflections.rb +0 -15
  62. data/test/dummy/config/initializers/mime_types.rb +0 -5
  63. data/test/dummy/config/initializers/secret_token.rb +0 -7
  64. data/test/dummy/config/initializers/session_store.rb +0 -8
  65. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  66. data/test/dummy/config/locales/en.yml +0 -5
  67. data/test/dummy/config/routes.rb +0 -4
  68. data/test/dummy/db/development.sqlite3 +0 -0
  69. data/test/dummy/db/schema.rb +0 -61
  70. data/test/dummy/log/development.log +0 -414
  71. data/test/dummy/public/404.html +0 -26
  72. data/test/dummy/public/422.html +0 -26
  73. data/test/dummy/public/500.html +0 -25
  74. data/test/dummy/script/rails +0 -6
  75. data/test/functional/comments_controller_test.rb +0 -181
  76. data/test/functional/subscriptions_controller_test.rb +0 -122
  77. data/test/integration/navigation_test.rb +0 -10
  78. data/test/test_helper.rb +0 -15
  79. data/test/unit/comment_test.rb +0 -35
  80. data/test/unit/helpers/comments_helper_test.rb +0 -4
  81. data/test/unit/helpers/subscriptions_helper_test.rb +0 -4
  82. data/test/unit/subscription_test.rb +0 -15
  83. data/test/unit/thread_test.rb +0 -57
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Commontator
2
2
 
3
3
  Commontator is a Rails engine for comments.
4
- That means it is fully functional as soon as you install and configure its gem, providing models, views and controllers of its own.
5
- At the same time, it is highly configurable, so you can change anything about it if you would like.
4
+ Being an engine means it is fully functional as soon as you install and configure its gem, providing models, views and controllers of its own.
5
+ At the same time, almost anything about it can be configured or customized to suit your needs.
6
6
 
7
7
  ## Installation
8
8
 
@@ -13,7 +13,8 @@ There are 4 steps you must follow to install commontator:
13
13
  Add this line to your application's Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'commontator', '~> 0.5.0'
16
+ gem 'commontator', '~> 0.5.0' or
17
+ gem 'commontator', '~> 1.0.0' (not yet released)
17
18
  ```
18
19
 
19
20
  And then execute:
@@ -93,6 +94,8 @@ Follow the steps below to add commontator to your models and views:
93
94
  ```
94
95
 
95
96
  Where commontable is an instance of some model that acts_as_commontable.
97
+ Note that model's record must already exist in the database, so do not use this in new.html.erb, _form.html.erb or similar.
98
+ We recommend you use this in the model's show.html.erb.
96
99
 
97
100
  3. Controllers
98
101
 
@@ -132,17 +135,51 @@ $ rake commontator:copy:models
132
135
 
133
136
  You are now free to modify them and have any changes made manifest in your application.
134
137
 
135
- ## Testing
136
-
137
- Soon
138
-
139
138
  ## Contributing
140
139
 
141
140
  1. Fork it
142
141
  2. Create your feature branch (`git checkout -b my-new-feature`)
143
- 3. Commit your changes (`git commit -am 'Added some feature'`)
144
- 4. Push to the branch (`git push origin my-new-feature`)
145
- 5. Create new Pull Request
142
+ 3. Write tests for your feature
143
+ 4. Implement your new feature
144
+ 5. Test your feature (`rake`)
145
+ 6. Commit your changes (`git commit -am 'Added some feature'`)
146
+ 7. Push to the branch (`git push origin my-new-feature`)
147
+ 8. Create new Pull Request
148
+
149
+ ## Development Environment Setup
150
+
151
+ 1. Browse to commontator's spec/dummy folder
152
+ 2. Use bundler to install all dependencies:
153
+
154
+ ```sh
155
+ $ bundle install
156
+ ```
157
+
158
+ 3. Load the schema:
159
+
160
+ ```sh
161
+ $ rake db:schema:load
162
+ ```
163
+
164
+ Or if the above fails:
165
+
166
+ ```sh
167
+ $ bundle exec rake db:schema:load
168
+ ```
169
+
170
+ ## Testing
171
+
172
+ To run all existing tests for commontator, simply execute the following from the main folder:
173
+
174
+ ```sh
175
+ $ rake
176
+ ```
177
+
178
+ Or if the above fails:
179
+
180
+ ```sh
181
+ $ bundle exec rake
182
+ ```
146
183
 
147
184
  ## License
148
185
 
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
20
20
  rdoc.rdoc_files.include('lib/**/*.rb')
21
21
  end
22
22
 
23
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
24
  load 'rails/tasks/engine.rake'
25
25
 
26
26
 
@@ -29,12 +29,13 @@ Bundler::GemHelper.install_tasks
29
29
 
30
30
  require 'rake/testtask'
31
31
 
32
- Rake::TestTask.new(:test) do |t|
32
+ Rake::TestTask.new(:spec) do |t|
33
+ Rake::Task['app:db:test:prepare'].invoke
33
34
  t.libs << 'lib'
34
- t.libs << 'test'
35
- t.pattern = 'test/**/*_test.rb'
35
+ t.libs << 'spec'
36
+ t.pattern = 'spec/**/*_spec.rb'
36
37
  t.verbose = false
37
38
  end
38
39
 
39
40
 
40
- task :default => :test
41
+ task :default => :spec
@@ -2,10 +2,12 @@ module Commontator
2
2
  class ApplicationController < ActionController::Base
3
3
  before_filter :get_user
4
4
 
5
+ rescue_from SecurityTransgression, :with => lambda { head(:forbidden) }
6
+
5
7
  protected
6
8
 
7
9
  def get_user
8
- @user = send Commontator.current_user_method
10
+ @user = self.send Commontator.current_user_method
9
11
  raise SecurityTransgression unless (@user.nil? || @user.is_commontator)
10
12
  end
11
13
 
@@ -2,10 +2,14 @@ module Commontator
2
2
  class ApplicationController < ActionController::Base
3
3
  before_filter :get_user
4
4
 
5
+ class SecurityTransgression < StandardError; end
6
+
7
+ rescue_from SecurityTransgression, :with => lambda { head(:forbidden) }
8
+
5
9
  protected
6
10
 
7
11
  def get_user
8
- @user = send Commontator.current_user_method
12
+ @user = self.send Commontator.current_user_method
9
13
  raise SecurityTransgression unless (@user.nil? || @user.is_commontator)
10
14
  end
11
15
 
@@ -13,7 +17,6 @@ module Commontator
13
17
  @thread = params[:thread_id].blank? ? \
14
18
  Commontator::Thread.find(params[:id]) : \
15
19
  Commontator::Thread.find(params[:thread_id])
16
- get_commontable_url
17
20
  end
18
21
 
19
22
  def get_commontable_url
@@ -13,7 +13,7 @@ module Commontator
13
13
  raise SecurityTransgression unless @comment.can_be_created_by?(@user)
14
14
 
15
15
  respond_to do |format|
16
- #format.html
16
+ format.html { redirect_to @thread }
17
17
  format.js
18
18
  end
19
19
 
@@ -29,9 +29,8 @@ module Commontator
29
29
 
30
30
  if @comment.save
31
31
  @thread.subscribe(@user) if @thread.config.auto_subscribe_on_comment
32
- @thread.mark_as_unread_except_for(@user)
32
+ @thread.add_unread_except_for(@user)
33
33
  SubscriptionsMailer.comment_created_email(@comment, @commontable_url)
34
- @thread.comment_created_callback(@user, @comment)
35
34
  else
36
35
  @errors = @comment.errors
37
36
  end
@@ -47,7 +46,7 @@ module Commontator
47
46
  raise SecurityTransgression unless @comment.can_be_edited_by?(@user)
48
47
 
49
48
  respond_to do |format|
50
- #format.html
49
+ format.html { redirect_to @thread }
51
50
  format.js
52
51
  end
53
52
  end
@@ -55,9 +54,8 @@ module Commontator
55
54
  # PUT /comments/1
56
55
  def update
57
56
  raise SecurityTransgression unless @comment.can_be_edited_by?(@user)
58
-
59
- @thread.comment_edited_callback(@user, @comment) \
60
- if @comment.update_attributes(params[:comment])
57
+
58
+ @comment.update_attributes(params[:comment])
61
59
 
62
60
  respond_to do |format|
63
61
  format.html { redirect_to @thread }
@@ -69,8 +67,8 @@ module Commontator
69
67
  def delete
70
68
  raise SecurityTransgression unless @comment.can_be_deleted_by?(@user)
71
69
 
72
- @comment.delete(@user)
73
- @thread.comment_deleted_callback(@user, @comment)
70
+ @comment.errors.add(:base, 'This comment has already been deleted.') \
71
+ unless @comment.delete(@user)
74
72
 
75
73
  respond_to do |format|
76
74
  format.html { redirect_to @thread }
@@ -82,7 +80,8 @@ module Commontator
82
80
  def undelete
83
81
  raise SecurityTransgression unless @comment.can_be_deleted_by?(@user)
84
82
 
85
- @comment.undelete
83
+ @comment.errors.add(:base, 'This comment is not deleted.') \
84
+ unless @comment.undelete
86
85
 
87
86
  respond_to do |format|
88
87
  format.html { redirect_to @thread }
@@ -13,7 +13,7 @@ module Commontator
13
13
  raise SecurityTransgression unless @comment.can_be_created_by?(@user)
14
14
 
15
15
  respond_to do |format|
16
- #format.html
16
+ format.html { redirect_to @thread }
17
17
  format.js
18
18
  end
19
19
 
@@ -29,9 +29,8 @@ module Commontator
29
29
 
30
30
  if @comment.save
31
31
  @thread.subscribe(@user) if @thread.config.auto_subscribe_on_comment
32
- @thread.mark_as_unread_except_for(@user)
32
+ @thread.add_unread_except_for(@user)
33
33
  SubscriptionsMailer.comment_created_email(@comment, @commontable_url)
34
- @thread.comment_created_callback(@user, @comment)
35
34
  else
36
35
  @errors = @comment.errors
37
36
  end
@@ -47,7 +46,7 @@ module Commontator
47
46
  raise SecurityTransgression unless @comment.can_be_edited_by?(@user)
48
47
 
49
48
  respond_to do |format|
50
- format.html
49
+ format.html { redirect_to @thread }
51
50
  format.js
52
51
  end
53
52
  end
@@ -55,9 +54,8 @@ module Commontator
55
54
  # PUT /comments/1
56
55
  def update
57
56
  raise SecurityTransgression unless @comment.can_be_edited_by?(@user)
58
-
59
- @thread.comment_edited_callback(@user, @comment) \
60
- if @comment.update_attributes(params[:comment])
57
+
58
+ @comment.update_attributes(params[:comment])
61
59
 
62
60
  respond_to do |format|
63
61
  format.html { redirect_to @thread }
@@ -69,8 +67,8 @@ module Commontator
69
67
  def delete
70
68
  raise SecurityTransgression unless @comment.can_be_deleted_by?(@user)
71
69
 
72
- @comment.delete(@user)
73
- @thread.comment_deleted_callback(@user, @comment)
70
+ @comment.errors.add(:base, 'This comment has already been deleted.') \
71
+ unless @comment.delete(@user)
74
72
 
75
73
  respond_to do |format|
76
74
  format.html { redirect_to @thread }
@@ -82,7 +80,8 @@ module Commontator
82
80
  def undelete
83
81
  raise SecurityTransgression unless @comment.can_be_deleted_by?(@user)
84
82
 
85
- @comment.undelete
83
+ @comment.errors.add(:base, 'This comment is not deleted.') \
84
+ unless @comment.undelete(@user)
86
85
 
87
86
  respond_to do |format|
88
87
  format.html { redirect_to @thread }
@@ -0,0 +1,22 @@
1
+ module Commontator
2
+ class CommontatorController < ActionController::Base
3
+ before_filter :get_user
4
+
5
+ protected
6
+
7
+ def get_user
8
+ @user = ApplicationController.send Commontator.current_user_method
9
+ raise SecurityTransgression unless (@user.nil? || @user.is_commontator)
10
+ end
11
+
12
+ def get_thread
13
+ @thread = params[:thread_id].blank? ? \
14
+ Commontator::Thread.find(params[:id]) : \
15
+ Commontator::Thread.find(params[:thread_id])
16
+ end
17
+
18
+ def get_commontable_url
19
+ @commontable_url = @thread.config.commontable_url_proc.call(main_app, @thread.commontable)
20
+ end
21
+ end
22
+ end
@@ -7,7 +7,7 @@ module Commontator
7
7
  def create
8
8
  raise SecurityTransgression unless @thread.can_subscribe?(@user)
9
9
 
10
- @thread.errors.add(:base, "You are already subscribed to this thread") \
10
+ @thread.errors.add(:subscription, "You are already subscribed to this thread") \
11
11
  unless @thread.subscribe(@user)
12
12
 
13
13
  respond_to do |format|
@@ -21,7 +21,7 @@ module Commontator
21
21
  def destroy
22
22
  raise SecurityTransgression unless @thread.can_subscribe?(@user)
23
23
 
24
- @thread.errors.add(:base, "You are not subscribed to this thread") \
24
+ @thread.errors.add(:subscription, "You are not subscribed to this thread") \
25
25
  unless @thread.unsubscribe(@user)
26
26
 
27
27
  respond_to do |format|
@@ -7,11 +7,11 @@ module Commontator
7
7
  def create
8
8
  raise SecurityTransgression unless @thread.can_subscribe?(@user)
9
9
 
10
- @thread.errors.add(:base, "You are already subscribed to this thread") \
10
+ @thread.errors.add(:subscription, "You are already subscribed to this thread") \
11
11
  unless @thread.subscribe(@user)
12
12
 
13
13
  respond_to do |format|
14
- format.html { redirect_to @commontable_url }
14
+ format.html { redirect_to @thread }
15
15
  format.js { render :subscribe }
16
16
  end
17
17
 
@@ -25,7 +25,7 @@ module Commontator
25
25
  unless @thread.unsubscribe(@user)
26
26
 
27
27
  respond_to do |format|
28
- format.html { redirect_to @commontable_url }
28
+ format.html { redirect_to @thread }
29
29
  format.js { render :subscribe }
30
30
  end
31
31
  end
@@ -17,8 +17,8 @@ module Commontator
17
17
  def close
18
18
  raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
19
19
 
20
- @thread.close(@user)
21
- @thread.thread_closed_callback(@user)
20
+ @thread.errors.add(:base, 'This thread has already been closed.') \
21
+ unless @thread.close(@user)
22
22
 
23
23
  respond_to do |format|
24
24
  format.html { redirect_to @thread }
@@ -30,7 +30,8 @@ module Commontator
30
30
  def reopen
31
31
  raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
32
32
 
33
- @thread.reopen
33
+ @thread.errors.add(:base, 'This thread is not closed.') \
34
+ unless @thread.reopen
34
35
 
35
36
  respond_to do |format|
36
37
  format.html { redirect_to @thread }
@@ -17,8 +17,8 @@ module Commontator
17
17
  def close
18
18
  raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
19
19
 
20
- @thread.close(@user)
21
- @thread.thread_closed_callback(@user)
20
+ @thread.errors.add(:base, "This thread has already been closed") \
21
+ unless @thread.close(@user)
22
22
 
23
23
  respond_to do |format|
24
24
  format.html { redirect_to @thread }
@@ -30,10 +30,12 @@ module Commontator
30
30
  def reopen
31
31
  raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
32
32
 
33
- @thread.reopen
33
+ @thread.errors.add(:base, "This thread is not closed") \
34
+ unless @thread.reopen
34
35
 
35
36
  respond_to do |format|
36
37
  format.html { redirect_to @thread }
38
+ format.js { render :show }
37
39
  end
38
40
  end
39
41
  end
@@ -0,0 +1,7 @@
1
+ module Commontator
2
+ module CommontatorHelper
3
+ def javascript_proc
4
+ Commontator.javascript_proc.call(self).html_safe
5
+ end
6
+ end
7
+ end
@@ -18,7 +18,8 @@ protected
18
18
  @thread = @comment.thread
19
19
  @creator = @comment.creator
20
20
 
21
- @bcc = @thread.subscribers.reject{|s| s == @creator}\
21
+ @bcc = @thread.subscribers.reject{|s| !s.commontator_config.subscription_emails || \
22
+ s == @creator} \
22
23
  .collect{|s| commontator_email(s)}
23
24
 
24
25
  return if @bcc.empty?
@@ -1,6 +1,7 @@
1
1
  module Commontator
2
2
  class SubscriptionsMailer < ActionMailer::Base
3
3
  include SharedHelper
4
+ include ThreadsHelper
4
5
 
5
6
  def comment_created_email(comment, commontable_url)
6
7
  setup_variables(comment, commontable_url)
@@ -17,7 +18,8 @@ protected
17
18
  @thread = @comment.thread
18
19
  @creator = @comment.creator
19
20
 
20
- @bcc = @thread.subscribers.reject{|s| s == @creator}\
21
+ @bcc = @thread.subscribers.reject{|s| s == @creator || \
22
+ !s.commontator_config.subscription_emails} \
21
23
  .collect{|s| commontator_email(s)}
22
24
 
23
25
  return if @bcc.empty?
@@ -8,15 +8,16 @@ module Commontator
8
8
 
9
9
  validates_presence_of :creator, :on => :create
10
10
  validates_presence_of :thread
11
+ validates_presence_of :body
11
12
 
12
13
  attr_accessible :body
13
14
 
14
- cattr_accessor :is_votable
15
- if respond_to?(:acts_as_votable)
16
- acts_as_votable if respond_to?(:acts_as_votable)
17
- self.is_votable = true
18
- else
19
- self.is_votable = false
15
+ cattr_accessor :acts_as_votable_initialized
16
+
17
+ def is_votable?
18
+ return false unless self.class.respond_to?(:acts_as_votable)
19
+ self.class.acts_as_votable unless acts_as_votable_initialized
20
+ self.class.acts_as_votable_initialized = true
20
21
  end
21
22
 
22
23
  def is_modified?
@@ -35,12 +36,14 @@ module Commontator
35
36
  end
36
37
 
37
38
  def delete(user = nil)
39
+ return false if is_deleted?
38
40
  self.deleted_at = Time.now
39
41
  self.deleter = user
40
42
  self.save!
41
43
  end
42
44
 
43
45
  def undelete
46
+ return false unless is_deleted?
44
47
  self.deleted_at = nil
45
48
  self.save!
46
49
  end
@@ -61,20 +64,21 @@ module Commontator
61
64
 
62
65
  def can_be_edited_by?(user)
63
66
  !thread.is_closed? && !is_deleted? &&\
64
- ((user == creator && thread.config.can_edit_own_comments) ||\
67
+ ((user == creator && thread.config.can_edit_own_comments && thread.can_be_read_by?(user)) ||\
65
68
  (thread.can_be_edited_by?(user) && thread.config.admin_can_edit_comments)) &&\
66
69
  (thread.comments.last == self || thread.config.can_edit_old_comments)
67
70
  end
68
71
 
69
72
  def can_be_deleted_by?(user)
70
73
  (!thread.is_closed? &&\
71
- ((user == creator && thread.config.can_delete_own_comments) &&\
74
+ ((user == creator && thread.config.can_delete_own_comments && \
75
+ thread.can_be_read_by?(user) && (!is_deleted? || deleter == user)) &&\
72
76
  (thread.comments.last == self || thread.config.can_delete_old_comments))) ||\
73
77
  thread.can_be_edited_by?(user)
74
78
  end
75
79
 
76
80
  def can_be_voted_on?
77
- is_votable && !is_deleted? && thread.config.comments_can_be_voted_on
81
+ is_votable? && !is_deleted? && thread.config.can_vote_on_comments
78
82
  end
79
83
 
80
84
  def can_be_voted_on_by?(user)