commontator 4.0.2 → 4.1.1
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 +4 -4
- data/README.md +3 -5
- data/app/assets/stylesheets/commontator/comments.css +16 -5
- data/app/assets/stylesheets/commontator/comments.css~ +98 -0
- data/app/controllers/commontator/application_controller.rb +6 -3
- data/app/controllers/commontator/application_controller.rb~ +30 -0
- data/app/controllers/commontator/threads_controller.rb +2 -0
- data/app/controllers/commontator/threads_controller.rb~ +44 -0
- data/app/helpers/commontator/threads_helper.rb +1 -8
- data/app/helpers/commontator/threads_helper.rb~ +11 -0
- data/app/mailers/commontator/subscriptions_mailer.rb +2 -4
- data/app/mailers/commontator/subscriptions_mailer.rb~ +50 -0
- data/app/models/commontator/comment.rb +23 -19
- data/app/models/commontator/comment.rb~ +106 -0
- data/app/models/commontator/thread.rb +10 -10
- data/app/models/commontator/thread.rb~ +124 -0
- data/app/views/commontator/comments/_show.html.erb +36 -34
- data/app/views/commontator/comments/_show.html.erb~ +47 -0
- data/app/views/commontator/comments/_votes.html.erb +6 -2
- data/app/views/commontator/comments/_votes.html.erb~ +61 -0
- data/app/views/commontator/comments/delete.js.erb +2 -2
- data/app/views/commontator/comments/delete.js.erb~ +17 -0
- data/app/views/commontator/comments/update.js.erb +2 -2
- data/app/views/commontator/comments/update.js.erb~ +7 -0
- data/app/views/commontator/subscriptions_mailer/comment_created.html.erb +2 -2
- data/app/views/commontator/subscriptions_mailer/comment_created.html.erb~ +6 -0
- data/app/views/commontator/threads/_show.html.erb +3 -7
- data/app/views/commontator/threads/_show.html.erb~ +58 -0
- data/config/initializers/commontator.rb +52 -47
- data/config/initializers/commontator.rb~ +176 -0
- data/lib/commontator.rb +6 -7
- data/lib/commontator.rb~ +61 -0
- data/lib/commontator/controller_includes.rb +1 -3
- data/lib/commontator/controller_includes.rb~ +22 -0
- data/lib/commontator/shared_helper.rb +3 -8
- data/lib/commontator/shared_helper.rb~ +37 -0
- data/lib/commontator/version.rb +1 -1
- data/lib/commontator/version.rb~ +3 -0
- data/spec/app/controllers/commontator/comments_controller_spec.rb +64 -45
- data/spec/app/controllers/commontator/comments_controller_spec.rb~ +580 -0
- data/spec/app/controllers/commontator/subscriptions_controller_spec.rb +3 -3
- data/spec/app/controllers/commontator/subscriptions_controller_spec.rb~ +99 -0
- data/spec/app/controllers/commontator/threads_controller_spec.rb +15 -9
- data/spec/app/controllers/commontator/threads_controller_spec.rb~ +126 -0
- data/spec/app/helpers/commontator/application_helper_spec.rb +1 -1
- data/spec/app/helpers/commontator/application_helper_spec.rb~ +9 -0
- data/spec/app/helpers/commontator/threads_helper_spec.rb +1 -5
- data/spec/app/helpers/commontator/threads_helper_spec.rb~ +13 -0
- data/spec/app/models/commontator/comment_spec.rb +4 -3
- data/spec/app/models/commontator/comment_spec.rb~ +62 -0
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/application.rb~ +27 -0
- data/spec/dummy/config/initializers/commontator.rb +67 -55
- data/spec/dummy/config/initializers/commontator.rb~ +176 -0
- data/spec/dummy/config/initializers/commontator2.rb~ +169 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +84489 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/02d4b791eb831cf2057bf4703a1218d1 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/0f196a1a50363b0a076ec6e1ee5417f6 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/a41c8be5379abec3c0d0d98e2f0d5609 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/e1f674c11941d62aac1764ef3a7134e4 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/e85565206c3e5fdf9dfeb367c85557b1 +0 -0
- data/spec/lib/commontator/commontable_config_spec.rb +1 -1
- data/spec/lib/commontator/commontable_config_spec.rb~ +26 -0
- data/spec/lib/commontator/commontator_config_spec.rb +5 -5
- data/spec/lib/commontator/commontator_config_spec.rb~ +26 -0
- data/spec/lib/commontator_spec.rb +6 -4
- data/spec/lib/commontator_spec.rb~ +28 -0
- data/spec/test_helper.rb +4 -4
- data/spec/test_helper.rb~ +37 -0
- metadata +46 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44192c2ae74567abb05fcbb08a8f9035435f8bd5
|
4
|
+
data.tar.gz: d99e1f12e46fbbbdaeb601b994ed5427d7a1bf7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5fd3c18561bb75f2fe5590dc462c72efe8931b00a2eea4e6aace1411fa37477f816de90daa881d5248b4aa3b21e62653140ef1853142848ba3980beaa8da97b
|
7
|
+
data.tar.gz: 0833ec342a5393094e9557a142503ac91ae9cf8d4676521fe3321ea0add1c0e5bac3690bdafe714f9fa204009d7e72743285c874cdfa8fc67a238e381554e8ec
|
data/README.md
CHANGED
@@ -95,12 +95,10 @@ Follow the steps below to add commontator to your models and views:
|
|
95
95
|
Where commontable is an instance of some model that acts_as_commontable.
|
96
96
|
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.
|
97
97
|
We recommend you use this in the model's show.html.erb.
|
98
|
-
When you do this, it is up to you to ensure that the user has the proper permission
|
99
|
-
to read the thread or else a SecurityTransgression will be raised.
|
100
98
|
|
101
99
|
3. Controllers
|
102
100
|
|
103
|
-
Instead of linking to the thread, you might want to have the thread display right away
|
101
|
+
Instead of linking to the thread, you might want to have the thread display right away when the corresponding view page is loaded.
|
104
102
|
If that's the case, add the following to the controller action that displays the view where the thread is located:
|
105
103
|
|
106
104
|
```ruby
|
@@ -109,7 +107,7 @@ Follow the steps below to add commontator to your models and views:
|
|
109
107
|
|
110
108
|
Note that the above method also checks the current user's read permission on the thread.
|
111
109
|
It will raise a SecurityTransgression if the user is not allowed to read the thread.
|
112
|
-
You can specify the
|
110
|
+
You can specify the proc that determines which users are allowed to read which threads in the initializer.
|
113
111
|
|
114
112
|
That's it! Commontator is now ready for use.
|
115
113
|
|
@@ -132,7 +130,7 @@ Note that acts_as_votable is currently incompatible with the protected_attribute
|
|
132
130
|
## Browser Support
|
133
131
|
|
134
132
|
No incompatibilities are currently known with any of the major browsers.
|
135
|
-
|
133
|
+
Commontator requires javascript enabled to function properly.
|
136
134
|
|
137
135
|
## Customization
|
138
136
|
|
@@ -25,18 +25,21 @@
|
|
25
25
|
|
26
26
|
.comment_body {
|
27
27
|
margin-left: 55px;
|
28
|
-
margin-top: -60px;
|
29
28
|
margin-right: 45px;
|
30
|
-
|
29
|
+
|
31
30
|
padding: 8px;
|
32
31
|
}
|
33
32
|
|
34
33
|
.comment_body p {
|
35
34
|
margin: 0px;
|
36
|
-
|
35
|
+
|
37
36
|
overflow: hidden;
|
38
37
|
}
|
39
38
|
|
39
|
+
.comment_div {
|
40
|
+
clear: both;
|
41
|
+
}
|
42
|
+
|
40
43
|
.comment_form_actions {
|
41
44
|
margin-top: 15px;
|
42
45
|
}
|
@@ -48,16 +51,20 @@
|
|
48
51
|
|
49
52
|
.comment_form_field textarea {
|
50
53
|
padding: 0px;
|
51
|
-
|
54
|
+
|
52
55
|
width: 100%;
|
53
56
|
}
|
54
57
|
|
55
|
-
.comment_gravatar_image
|
58
|
+
.comment_gravatar_image {
|
59
|
+
float: left;
|
60
|
+
|
56
61
|
margin-top: 5px;
|
62
|
+
margin-bottom: 5px;
|
57
63
|
}
|
58
64
|
|
59
65
|
.comment_timestamp {
|
60
66
|
color: #777;
|
67
|
+
display: inline-block;
|
61
68
|
}
|
62
69
|
|
63
70
|
.comment_votes {
|
@@ -74,6 +81,10 @@
|
|
74
81
|
margin: 0px;
|
75
82
|
}
|
76
83
|
|
84
|
+
.comment_votes form {
|
85
|
+
margin: 0px;
|
86
|
+
}
|
87
|
+
|
77
88
|
.comment_vote_count p {
|
78
89
|
margin: 0px;
|
79
90
|
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
.comment {
|
2
|
+
font-size: 12px;
|
3
|
+
font-weight: normal;
|
4
|
+
font-style: normal;
|
5
|
+
|
6
|
+
border-top: 1px solid;
|
7
|
+
border-left: 1px solid;
|
8
|
+
|
9
|
+
margin-top: 15px;
|
10
|
+
margin-bottom: 15px;
|
11
|
+
|
12
|
+
padding-top: 8px;
|
13
|
+
padding-left: 15px;
|
14
|
+
|
15
|
+
color: #000;
|
16
|
+
border-color: #ddd;
|
17
|
+
background-color: #fff;
|
18
|
+
|
19
|
+
clear: both;
|
20
|
+
}
|
21
|
+
|
22
|
+
.comment_actions {
|
23
|
+
float: right;
|
24
|
+
}
|
25
|
+
|
26
|
+
.comment_body {
|
27
|
+
margin-left: 55px;
|
28
|
+
margin-right: 45px;
|
29
|
+
|
30
|
+
padding: 8px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.comment_body p {
|
34
|
+
margin: 0px;
|
35
|
+
|
36
|
+
overflow: hidden;
|
37
|
+
}
|
38
|
+
|
39
|
+
.comment_div {
|
40
|
+
clear: both;
|
41
|
+
}
|
42
|
+
|
43
|
+
.comment_form_actions {
|
44
|
+
margin-top: 15px;
|
45
|
+
}
|
46
|
+
|
47
|
+
.comment_form_field > .field_with_errors {
|
48
|
+
display: block;
|
49
|
+
padding-right: 4px;
|
50
|
+
}
|
51
|
+
|
52
|
+
.comment_form_field textarea {
|
53
|
+
padding: 0px;
|
54
|
+
|
55
|
+
width: 100%;
|
56
|
+
}
|
57
|
+
|
58
|
+
.comment_gravatar_image {
|
59
|
+
float: left;
|
60
|
+
|
61
|
+
margin-top: 5px;
|
62
|
+
margin-bottom: 5px;
|
63
|
+
}
|
64
|
+
|
65
|
+
.comment_timestamp {
|
66
|
+
color: #777;
|
67
|
+
display: inline-block;
|
68
|
+
}
|
69
|
+
|
70
|
+
.comment_votes {
|
71
|
+
float: right;
|
72
|
+
|
73
|
+
text-align: center;
|
74
|
+
}
|
75
|
+
|
76
|
+
.comment_votes input,
|
77
|
+
.comment_votes img {
|
78
|
+
border: none;
|
79
|
+
background-color: transparent;
|
80
|
+
padding: 0px;
|
81
|
+
margin: 0px;
|
82
|
+
}
|
83
|
+
|
84
|
+
.comment_votes form {
|
85
|
+
border: none;
|
86
|
+
background-color: transparent;
|
87
|
+
padding: 0px;
|
88
|
+
margin: 0px;
|
89
|
+
}
|
90
|
+
|
91
|
+
.comment_vote_count p {
|
92
|
+
margin: 0px;
|
93
|
+
}
|
94
|
+
|
95
|
+
.comment_votes span {
|
96
|
+
padding: 0px;
|
97
|
+
margin: 0px;
|
98
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Commontator
|
2
2
|
class ApplicationController < ActionController::Base
|
3
|
-
before_filter :get_user
|
3
|
+
before_filter :get_user, :ensure_user
|
4
4
|
|
5
5
|
cattr_accessor :commontable_url
|
6
6
|
|
@@ -9,8 +9,11 @@ module Commontator
|
|
9
9
|
protected
|
10
10
|
|
11
11
|
def get_user
|
12
|
-
@user =
|
13
|
-
|
12
|
+
@user = Commontator.current_user_proc.call(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def ensure_user
|
16
|
+
raise SecurityTransgression unless (@user && @user.is_commontator)
|
14
17
|
end
|
15
18
|
|
16
19
|
def get_thread
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Commontator
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
before_filter :get_user, :ensure_user
|
4
|
+
|
5
|
+
cattr_accessor :commontable_url
|
6
|
+
|
7
|
+
rescue_from SecurityTransgression, :with => lambda { head(:forbidden) }
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def get_user
|
12
|
+
@user = self.send Commontator.current_user_method
|
13
|
+
end
|
14
|
+
|
15
|
+
def ensure_user
|
16
|
+
raise SecurityTransgression unless (@user && @user.is_commontator)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_thread
|
20
|
+
@thread = params[:thread_id].blank? ? \
|
21
|
+
Commontator::Thread.find(params[:id]) : \
|
22
|
+
Commontator::Thread.find(params[:thread_id])
|
23
|
+
raise SecurityTransgression if @thread.commontable.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_commontable_url
|
27
|
+
self.commontable_url = @thread.config.commontable_url_proc.call(main_app, @thread.commontable)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Commontator
|
2
|
+
class ThreadsController < Commontator::ApplicationController
|
3
|
+
skip_before_filter :ensure_user, :only => :index
|
4
|
+
|
5
|
+
before_filter :get_thread
|
6
|
+
before_filter :set_commontable_url, :only => :show
|
7
|
+
|
8
|
+
# GET /threads/1
|
9
|
+
def show
|
10
|
+
commontator_thread_show(@thread.commontable)
|
11
|
+
|
12
|
+
respond_to do |format|
|
13
|
+
format.html { redirect_to commontable_url }
|
14
|
+
format.js
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# PUT /threads/1/close
|
19
|
+
def close
|
20
|
+
raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
|
21
|
+
|
22
|
+
@thread.errors.add(:base, 'This thread has already been closed.') \
|
23
|
+
unless @thread.close(@user)
|
24
|
+
|
25
|
+
respond_to do |format|
|
26
|
+
format.html { redirect_to @thread }
|
27
|
+
format.js { render :show }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# PUT /threads/1/reopen
|
32
|
+
def reopen
|
33
|
+
raise SecurityTransgression unless @thread.can_be_edited_by?(@user)
|
34
|
+
|
35
|
+
@thread.errors.add(:base, 'This thread is not closed.') \
|
36
|
+
unless @thread.reopen
|
37
|
+
|
38
|
+
respond_to do |format|
|
39
|
+
format.html { redirect_to @thread }
|
40
|
+
format.js { render :show }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,14 +1,7 @@
|
|
1
1
|
module Commontator
|
2
2
|
module ThreadsHelper
|
3
3
|
def commontable_name(thread)
|
4
|
-
config
|
5
|
-
config.commontable_name.blank? ? \
|
6
|
-
thread.commontable.class.name : \
|
7
|
-
config.commontable_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def commontable_id(thread)
|
11
|
-
thread.commontable.send(thread.config.commontable_id_method)
|
4
|
+
thread.config.commontable_name_proc.call(thread.commontable)
|
12
5
|
end
|
13
6
|
end
|
14
7
|
end
|
@@ -23,10 +23,9 @@ module Commontator
|
|
23
23
|
@config = @thread.config
|
24
24
|
|
25
25
|
@creator_name = commontator_name(@creator)
|
26
|
-
@
|
26
|
+
@comment_created_timestamp = @comment.created_timestamp
|
27
27
|
|
28
28
|
@commontable_name = commontable_name(@thread)
|
29
|
-
@commontable_id = commontable_id(@thread).to_s
|
30
29
|
|
31
30
|
@commontable_url = ApplicationController.commontable_url
|
32
31
|
|
@@ -37,9 +36,8 @@ module Commontator
|
|
37
36
|
params[:commontable] = @commontable
|
38
37
|
params[:config] = @config
|
39
38
|
params[:creator_name] = @creator_name
|
40
|
-
params[:
|
39
|
+
params[:comment_created_timestamp] = @comment_created_timestamp
|
41
40
|
params[:commontable_name] = @commontable_name
|
42
|
-
params[:commontable_id] = @commontable_id
|
43
41
|
params[:commontable_url] = @commontable_url
|
44
42
|
|
45
43
|
@bcc = recipients.collect{|s| commontator_email(s)}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Commontator
|
2
|
+
class SubscriptionsMailer < ActionMailer::Base
|
3
|
+
include SharedHelper
|
4
|
+
include ThreadsHelper
|
5
|
+
|
6
|
+
def comment_created(comment, recipients)
|
7
|
+
setup_variables(comment, recipients)
|
8
|
+
|
9
|
+
mail :to => 'Undisclosed Recipients',
|
10
|
+
:bcc => @bcc,
|
11
|
+
:from => @from,
|
12
|
+
:subject => @subject
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def setup_variables(comment, recipients)
|
18
|
+
@comment = comment
|
19
|
+
@thread = @comment.thread
|
20
|
+
@creator = @comment.creator
|
21
|
+
|
22
|
+
@commontable = @thread.commontable
|
23
|
+
@config = @thread.config
|
24
|
+
|
25
|
+
@creator_name = commontator_name(@creator)
|
26
|
+
@comment_created_timestamp = @comment.created_timestamp
|
27
|
+
|
28
|
+
@commontable_name = commontable_name(@thread)
|
29
|
+
@commontable_id = commontable_id(@thread).to_s
|
30
|
+
|
31
|
+
@commontable_url = ApplicationController.commontable_url
|
32
|
+
|
33
|
+
params = Hash.new
|
34
|
+
params[:comment] = @comment
|
35
|
+
params[:thread] = @thread
|
36
|
+
params[:creator] = @creator
|
37
|
+
params[:commontable] = @commontable
|
38
|
+
params[:config] = @config
|
39
|
+
params[:creator_name] = @creator_name
|
40
|
+
params[:comment_created_timestamp] = @comment_created_timestamp
|
41
|
+
params[:commontable_name] = @commontable_name
|
42
|
+
params[:commontable_id] = @commontable_id
|
43
|
+
params[:commontable_url] = @commontable_url
|
44
|
+
|
45
|
+
@bcc = recipients.collect{|s| commontator_email(s)}
|
46
|
+
@from = @config.subscription_email_from_proc.call(params)
|
47
|
+
@subject = @config.subscription_email_subject_proc.call(params)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -28,7 +28,7 @@ module Commontator
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def get_vote_by(user)
|
31
|
-
return nil unless is_votable?
|
31
|
+
return nil unless is_votable? && user && user.is_commontator
|
32
32
|
votes.where(:voter_type => user.class.name, :voter_id => user.id).first
|
33
33
|
end
|
34
34
|
|
@@ -54,12 +54,16 @@ module Commontator
|
|
54
54
|
self.save
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
57
|
+
def created_timestamp
|
58
58
|
config = thread.config
|
59
59
|
"#{config.comment_create_verb_past.capitalize} on " + \
|
60
|
-
created_at.strftime(config.timestamp_format)
|
61
|
-
|
62
|
-
|
60
|
+
created_at.strftime(config.timestamp_format)
|
61
|
+
end
|
62
|
+
|
63
|
+
def updated_timestamp
|
64
|
+
config = thread.config
|
65
|
+
is_modified? ? ("Last #{config.comment_edit_verb_past} on " + \
|
66
|
+
updated_at.strftime(config.timestamp_format)) : ''
|
63
67
|
end
|
64
68
|
|
65
69
|
##################
|
@@ -67,28 +71,28 @@ module Commontator
|
|
67
71
|
##################
|
68
72
|
|
69
73
|
def can_be_read_by?(user)
|
70
|
-
(thread.
|
71
|
-
|
72
|
-
|
74
|
+
((!is_deleted? || thread.config.deleted_comments_are_visible) &&\
|
75
|
+
thread.can_be_read_by?(user)) ||\
|
76
|
+
thread.can_be_edited_by?(user)
|
73
77
|
end
|
74
78
|
|
75
79
|
def can_be_created_by?(user)
|
76
|
-
!thread.is_closed? && thread.can_be_read_by?(user)
|
80
|
+
!thread.is_closed? && user == creator && thread.can_be_read_by?(user)
|
77
81
|
end
|
78
82
|
|
79
83
|
def can_be_edited_by?(user)
|
80
|
-
!thread.is_closed? && !is_deleted? &&\
|
81
|
-
(
|
82
|
-
|
83
|
-
|
84
|
+
(!thread.is_closed? && !is_deleted? &&\
|
85
|
+
(thread.comments.last == self || thread.config.can_edit_old_comments) &&\
|
86
|
+
user == creator && thread.config.can_edit_own_comments && thread.can_be_read_by?(user)) ||\
|
87
|
+
(thread.config.admin_can_edit_comments && thread.can_be_edited_by?(user))
|
84
88
|
end
|
85
89
|
|
86
90
|
def can_be_deleted_by?(user)
|
87
|
-
(!thread.is_closed? &&\
|
88
|
-
(
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
(!thread.is_closed? && (!is_deleted? || editor == user) &&\
|
92
|
+
(thread.comments.last == self || thread.config.can_delete_old_comments) &&\
|
93
|
+
user == creator && thread.config.can_delete_own_comments &&\
|
94
|
+
thread.can_be_read_by?(user)) ||\
|
95
|
+
thread.can_be_edited_by?(user)
|
92
96
|
end
|
93
97
|
|
94
98
|
def can_be_voted_on?
|
@@ -96,7 +100,7 @@ module Commontator
|
|
96
100
|
end
|
97
101
|
|
98
102
|
def can_be_voted_on_by?(user)
|
99
|
-
can_be_voted_on? &&
|
103
|
+
can_be_voted_on? && user && user.is_commontator && user != creator && thread.can_be_read_by?(user)
|
100
104
|
end
|
101
105
|
end
|
102
106
|
end
|