the_comments_ruby 2.3.3

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 (172) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.ruby-gemset.example +1 -0
  4. data/.ruby-version.example +1 -0
  5. data/.rvmrc.example +1 -0
  6. data/.travis.yml +5 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +338 -0
  10. data/Rakefile +1 -0
  11. data/app/assets/javascripts/the_comments.js.coffee +108 -0
  12. data/app/assets/javascripts/the_comments_manage.js.coffee +27 -0
  13. data/app/assets/stylesheets/the_comments.css.scss +248 -0
  14. data/app/controllers/_templates_/comments_controller.rb +44 -0
  15. data/app/controllers/concerns/the_comments/controller.rb +197 -0
  16. data/app/controllers/concerns/the_comments/view_token.rb +20 -0
  17. data/app/helpers/render_comments_tree_helper.rb +111 -0
  18. data/app/models/_templates_/comment.rb +38 -0
  19. data/app/models/concerns/the_comments/comment.rb +116 -0
  20. data/app/models/concerns/the_comments/comment_states.rb +80 -0
  21. data/app/models/concerns/the_comments/commentable.rb +69 -0
  22. data/app/models/concerns/the_comments/user.rb +56 -0
  23. data/app/views/the_comments/_tree.html.erb +3 -0
  24. data/app/views/the_comments/haml/_additional_info.html.haml +13 -0
  25. data/app/views/the_comments/haml/_comment.html.haml +1 -0
  26. data/app/views/the_comments/haml/_comment_body.html.haml +25 -0
  27. data/app/views/the_comments/haml/_comment_edit.html.haml +26 -0
  28. data/app/views/the_comments/haml/_form.html.haml +8 -0
  29. data/app/views/the_comments/haml/_guest_form.html.haml +22 -0
  30. data/app/views/the_comments/haml/_logined_form.html.haml +18 -0
  31. data/app/views/the_comments/haml/_manage_controls.html.haml +30 -0
  32. data/app/views/the_comments/haml/_sidebar.html.haml +9 -0
  33. data/app/views/the_comments/haml/_sidebar_admin.html.haml +12 -0
  34. data/app/views/the_comments/haml/_sidebar_backlink.html.haml +3 -0
  35. data/app/views/the_comments/haml/_sidebar_user.html.haml +29 -0
  36. data/app/views/the_comments/haml/_tree.html.haml +16 -0
  37. data/app/views/the_comments/haml/manage.html.haml +26 -0
  38. data/app/views/the_comments/slim/_additional_info.html.slim +13 -0
  39. data/app/views/the_comments/slim/_comment.html.slim +1 -0
  40. data/app/views/the_comments/slim/_comment_body.html.slim +24 -0
  41. data/app/views/the_comments/slim/_comment_edit.html.slim +26 -0
  42. data/app/views/the_comments/slim/_form.html.slim +8 -0
  43. data/app/views/the_comments/slim/_guest_form.html.slim +22 -0
  44. data/app/views/the_comments/slim/_logined_form.html.slim +18 -0
  45. data/app/views/the_comments/slim/_manage_controls.html.slim +30 -0
  46. data/app/views/the_comments/slim/_sidebar.html.slim +9 -0
  47. data/app/views/the_comments/slim/_sidebar_admin.html.slim +12 -0
  48. data/app/views/the_comments/slim/_sidebar_backlink.html.slim +3 -0
  49. data/app/views/the_comments/slim/_sidebar_user.html.slim +29 -0
  50. data/app/views/the_comments/slim/_tree.html.slim +16 -0
  51. data/app/views/the_comments/slim/index.html.slim +18 -0
  52. data/app/views/the_comments/slim/manage.html.slim +26 -0
  53. data/app/views/the_comments/slim/my_comments.html.slim +28 -0
  54. data/config/initializers/the_comments.rb +14 -0
  55. data/config/locales/en.yml +68 -0
  56. data/config/locales/ru.yml +71 -0
  57. data/config/routes.rb +38 -0
  58. data/db/migrate/20130101010101_the_comments_change_user.rb +18 -0
  59. data/db/migrate/20130101010102_the_comments_create_comments.rb +50 -0
  60. data/db/migrate/20130101010103_the_comments_change_commentable.rb +13 -0
  61. data/docs/admin_ui_installation.md +145 -0
  62. data/docs/advanced_installation.md +185 -0
  63. data/docs/comment_api.md +58 -0
  64. data/docs/commentable_api.md +59 -0
  65. data/docs/config_file.md +27 -0
  66. data/docs/content_preprocessors.md +73 -0
  67. data/docs/customazation_of_views.md +30 -0
  68. data/docs/denormalization_and_recent_comments.md +40 -0
  69. data/docs/documentation.md +29 -0
  70. data/docs/generators.md +74 -0
  71. data/docs/pagination.md +123 -0
  72. data/docs/routes.md +77 -0
  73. data/docs/screencast.jpg +0 -0
  74. data/docs/the_comments.jpg +0 -0
  75. data/docs/the_comments_view_1.gif +0 -0
  76. data/docs/the_comments_view_2.gif +0 -0
  77. data/docs/the_comments_view_3.gif +0 -0
  78. data/docs/the_comments_view_4.gif +0 -0
  79. data/docs/the_comments_view_5.gif +0 -0
  80. data/docs/user_api.md +75 -0
  81. data/docs/what_is_comcoms.md +63 -0
  82. data/docs/whats_wrong_with_other_gems.md +28 -0
  83. data/docs/where_is_example_application.md +37 -0
  84. data/gem_version.rb +3 -0
  85. data/lib/generators/the_comments/USAGE +44 -0
  86. data/lib/generators/the_comments/the_comments_generator.rb +56 -0
  87. data/lib/generators/the_comments/views_generator.rb +79 -0
  88. data/lib/the_comments/config.rb +37 -0
  89. data/lib/the_comments/version.rb +1 -0
  90. data/lib/the_comments.rb +28 -0
  91. data/spec/dummy_app/.gitignore +18 -0
  92. data/spec/dummy_app/.rspec +1 -0
  93. data/spec/dummy_app/Gemfile +43 -0
  94. data/spec/dummy_app/README.md +33 -0
  95. data/spec/dummy_app/Rakefile +6 -0
  96. data/spec/dummy_app/app/assets/images/.keep +0 -0
  97. data/spec/dummy_app/app/assets/javascripts/admin_panel.js +5 -0
  98. data/spec/dummy_app/app/assets/javascripts/application.js +16 -0
  99. data/spec/dummy_app/app/assets/stylesheets/admin_panel.css +3 -0
  100. data/spec/dummy_app/app/assets/stylesheets/app.css.scss +4 -0
  101. data/spec/dummy_app/app/assets/stylesheets/application.css +16 -0
  102. data/spec/dummy_app/app/controllers/application_controller.rb +7 -0
  103. data/spec/dummy_app/app/controllers/comments_controller.rb +28 -0
  104. data/spec/dummy_app/app/controllers/concerns/.keep +0 -0
  105. data/spec/dummy_app/app/controllers/posts_controller.rb +13 -0
  106. data/spec/dummy_app/app/controllers/users_controller.rb +7 -0
  107. data/spec/dummy_app/app/helpers/application_helper.rb +2 -0
  108. data/spec/dummy_app/app/mailers/.keep +0 -0
  109. data/spec/dummy_app/app/models/.keep +0 -0
  110. data/spec/dummy_app/app/models/comment.rb +32 -0
  111. data/spec/dummy_app/app/models/concerns/.keep +0 -0
  112. data/spec/dummy_app/app/models/post.rb +17 -0
  113. data/spec/dummy_app/app/models/user.rb +21 -0
  114. data/spec/dummy_app/app/views/layouts/admin.html.haml +25 -0
  115. data/spec/dummy_app/app/views/layouts/application.html.haml +20 -0
  116. data/spec/dummy_app/app/views/posts/index.html.haml +22 -0
  117. data/spec/dummy_app/app/views/posts/show.html.haml +7 -0
  118. data/spec/dummy_app/bin/bundle +3 -0
  119. data/spec/dummy_app/bin/rails +4 -0
  120. data/spec/dummy_app/bin/rake +4 -0
  121. data/spec/dummy_app/config/application.rb +23 -0
  122. data/spec/dummy_app/config/boot.rb +4 -0
  123. data/spec/dummy_app/config/database.yml +11 -0
  124. data/spec/dummy_app/config/environment.rb +5 -0
  125. data/spec/dummy_app/config/environments/development.rb +29 -0
  126. data/spec/dummy_app/config/environments/production.rb +80 -0
  127. data/spec/dummy_app/config/environments/test.rb +36 -0
  128. data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  129. data/spec/dummy_app/config/initializers/filter_parameter_logging.rb +4 -0
  130. data/spec/dummy_app/config/initializers/inflections.rb +16 -0
  131. data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
  132. data/spec/dummy_app/config/initializers/secret_token.rb +12 -0
  133. data/spec/dummy_app/config/initializers/session_store.rb +3 -0
  134. data/spec/dummy_app/config/initializers/sorcery.rb +437 -0
  135. data/spec/dummy_app/config/initializers/the_comments.rb +14 -0
  136. data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
  137. data/spec/dummy_app/config/locales/en.yml +23 -0
  138. data/spec/dummy_app/config/routes.rb +19 -0
  139. data/spec/dummy_app/config.ru +4 -0
  140. data/spec/dummy_app/db/migrate/20130712061503_sorcery_core.rb +16 -0
  141. data/spec/dummy_app/db/migrate/20130712065951_create_posts.rb +11 -0
  142. data/spec/dummy_app/db/migrate/20131027185332_change_user.the_comments_engine.rb +19 -0
  143. data/spec/dummy_app/db/migrate/20131027185333_create_comments.the_comments_engine.rb +51 -0
  144. data/spec/dummy_app/db/migrate/20131027185334_change_commentable.the_comments_engine.rb +14 -0
  145. data/spec/dummy_app/db/schema.rb +74 -0
  146. data/spec/dummy_app/db/seeds.rb +42 -0
  147. data/spec/dummy_app/lib/assets/.keep +0 -0
  148. data/spec/dummy_app/lib/tasks/.keep +0 -0
  149. data/spec/dummy_app/lib/tasks/app_bootstrap.rake +15 -0
  150. data/spec/dummy_app/log/.keep +0 -0
  151. data/spec/dummy_app/public/404.html +58 -0
  152. data/spec/dummy_app/public/422.html +58 -0
  153. data/spec/dummy_app/public/500.html +57 -0
  154. data/spec/dummy_app/public/favicon.ico +0 -0
  155. data/spec/dummy_app/public/robots.txt +5 -0
  156. data/spec/dummy_app/spec/factories/post.rb +6 -0
  157. data/spec/dummy_app/spec/factories/user.rb +6 -0
  158. data/spec/dummy_app/spec/models/user_counters_spec.rb +339 -0
  159. data/spec/dummy_app/spec/spec_helper.rb +29 -0
  160. data/spec/dummy_app/test/controllers/.keep +0 -0
  161. data/spec/dummy_app/test/fixtures/.keep +0 -0
  162. data/spec/dummy_app/test/helpers/.keep +0 -0
  163. data/spec/dummy_app/test/integration/.keep +0 -0
  164. data/spec/dummy_app/test/mailers/.keep +0 -0
  165. data/spec/dummy_app/test/models/.keep +0 -0
  166. data/spec/dummy_app/test/test_helper.rb +15 -0
  167. data/spec/dummy_app/vendor/assets/javascripts/.keep +0 -0
  168. data/spec/dummy_app/vendor/assets/stylesheets/.keep +0 -0
  169. data/the_comments.gemspec +25 -0
  170. data/the_comments.yml.teamocil.example +11 -0
  171. data/views_converter.rb +16 -0
  172. metadata +333 -0
@@ -0,0 +1,248 @@
1
+ .comments_tree, .comments_list{
2
+ font-family: Arial;
3
+
4
+ margin:0;
5
+ padding:0;
6
+ margin-bottom: 30px;
7
+
8
+ *{ margin: 0; padding: 0; font-size: inherit; }
9
+
10
+ a{ text-decoration: none; }
11
+ a:hover{ text-decoration: underline; }
12
+
13
+ ol{
14
+ margin: 0;
15
+ padding: 0 0 0 20px;
16
+ list-style: none outside none;
17
+ }
18
+ li{
19
+ margin-bottom: 5px;
20
+ position: relative;
21
+ list-style: none outside none;
22
+ }
23
+ }
24
+
25
+ .action_btns a{ margin-right: 15px; }
26
+
27
+ .comments, .comments_tree{
28
+ font-family: Arial;
29
+ font-size: 13px;
30
+
31
+ h3{ font-size: 1.6em; }
32
+
33
+ .error_notifier{
34
+ background-color: #F2DEDE;
35
+ border: 1px solid #B94A48;
36
+ color: #B94A48;
37
+
38
+ border-radius: 4px;
39
+ margin: 0 0 15px 0;
40
+ padding: 10px 10px 0 10px;
41
+ overflow: hidden;
42
+
43
+ p{ margin: 0 0 10px 0; }
44
+ }
45
+ form{
46
+
47
+ background: #e0e4f5;
48
+
49
+ border: 1px solid #c6cff5;
50
+ border-radius: 5px;
51
+ padding: 10px;
52
+
53
+ p{ margin: 0 0 10px 0; }
54
+
55
+ input[type=text]{
56
+ border: 1px solid gray;
57
+ padding: 4px;
58
+ width: 75%;
59
+ }
60
+ label{ font-size: 15px; }
61
+ textarea{
62
+ border: 1px solid gray;
63
+ font-family: Arial;
64
+ font-size: 13px;
65
+ height: 150px;
66
+ padding: 4px;
67
+ width: 75%;
68
+ }
69
+ .trap{
70
+ margin: 0; padding: 0;
71
+ filter: alpha(opacity=0.001);
72
+ height: 0.1px;
73
+ opacity: 0.001;
74
+ overflow: hidden;
75
+ }
76
+ }
77
+ }
78
+
79
+ .comments_tree{
80
+ .nested_set{
81
+ border-left: 1px dotted lightGray;
82
+ }
83
+
84
+ li{
85
+ .comment.draft{
86
+ border: 1px solid gray;
87
+ background: #eff5f3;
88
+ padding: 10px;
89
+ }
90
+ }
91
+
92
+ .form_holder{ margin-left: 40px; }
93
+
94
+ .edit, .delete{
95
+ margin-bottom: 3px;
96
+ text-align:center;
97
+ line-height: 130%;
98
+ background: #336;
99
+ color: white;
100
+ padding: 1px;
101
+ }
102
+ .delete{ background: gray; }
103
+
104
+ .comment{
105
+ overflow: hidden; zoom: 1;
106
+
107
+ .userpic{
108
+ overflow: hidden; zoom: 1;
109
+ float: left;
110
+ width: 50px;
111
+
112
+ img{ margin-bottom: 10px; width: 42px; height: 42px; }
113
+ }
114
+ .userbar, .cbody{
115
+ margin: 0 0 5px 55px;
116
+ padding: 3px;
117
+ }
118
+ .userbar{
119
+ background: #eff5f3;
120
+ border-radius: 3px;
121
+ padding-left: 7px;
122
+ }
123
+ &.draft{
124
+ .userbar{ background: #ffa768; }
125
+ .to_draft{ display: none; }
126
+ }
127
+ &.published{
128
+ .to_published{ display: none; }
129
+ }
130
+ .cbody{
131
+ font-size: 15px;
132
+ border-bottom: 1px solid #eee;
133
+ padding-bottom: 10px;
134
+ line-height: 135%;
135
+ margin-bottom: 3px;
136
+ overflow: hidden;
137
+ }
138
+ .reply{
139
+ margin: 0 0 5px 55px;
140
+ font-size: 12px;
141
+ }
142
+ }
143
+
144
+ .controls{
145
+ position: absolute;
146
+ top: 53px; left: 5px;
147
+
148
+ a{
149
+ font-size:11px;
150
+ display:block;
151
+ }
152
+ }
153
+
154
+ .comment{
155
+ margin-bottom: 10px;
156
+
157
+ &.published, &.draft{
158
+ margin-bottom: 10px;
159
+ border-radius: 3px;
160
+ padding: 5px;
161
+ }
162
+ &.highlighted{ border: 1px dashed #ff6633 !important; }
163
+
164
+ }
165
+
166
+ .form_holder{
167
+ form{ margin: 10px 0; }
168
+ }
169
+ }
170
+
171
+ .new_comment{
172
+ .btn{
173
+ padding: 7px;
174
+ margin-top: 5px;
175
+ cursor: pointer;
176
+ }
177
+ }
178
+
179
+ .comments_list{
180
+ li{
181
+ margin-bottom: 20px;
182
+
183
+ .item{
184
+ border: 1px solid gray;
185
+ border-radius: 5px;
186
+ padding: 10px;
187
+ }
188
+
189
+ .draft{
190
+ border-left: 5px solid orange;
191
+
192
+ .controls{
193
+ a.to_draft{ display: none }
194
+ }
195
+ }
196
+ .published{
197
+ border-left: 5px solid green;
198
+
199
+ .controls{
200
+ a.to_published{ display: none; }
201
+ }
202
+ }
203
+
204
+ .deleted{
205
+ border-left: 5px solid red;
206
+
207
+ .controls{
208
+ a.to_deleted, a.to_spam{ display: none; }
209
+ }
210
+ }
211
+
212
+ .comment{
213
+ div{ margin: 0 0 10px 0; }
214
+
215
+ label{
216
+ width: 75px;
217
+ font-weight: bold;
218
+ display: inline-block;
219
+ }
220
+ input[type=text]{
221
+ width: 70%;
222
+ padding: 4px;
223
+ }
224
+ input[type=submit]{
225
+ padding: 5px;
226
+ cursor: pointer;
227
+ }
228
+ textarea{
229
+ width: 70%;
230
+ padding: 4px;
231
+ height: 150px;
232
+ }
233
+ .content{
234
+ line-height: 130%;
235
+ background: #ddd;
236
+ padding: 10px;
237
+ }
238
+ .commentable{
239
+ margin-bottom: 10px;
240
+ }
241
+ .controls{
242
+ background: lightgray;
243
+ padding: 3px;
244
+ a{ margin-right: 15px; }
245
+ }
246
+ }
247
+ }
248
+ }
@@ -0,0 +1,44 @@
1
+ class CommentsController < ApplicationController
2
+ # layout 'admin'
3
+
4
+ # Define your restrict methods and use them like this:
5
+ #
6
+ # before_action :user_required, except: %w[index create]
7
+ # before_action :owner_required, except: %w[index create]
8
+ # before_action :admin_required, only: %w[total_draft total_published total_deleted total_spam]
9
+
10
+ include TheComments::Controller
11
+
12
+ # >>> include TheComments::Controller <<<
13
+ # (!) Almost all methods based on *current_user* method
14
+ #
15
+ # 1. Controller's public methods list:
16
+ # You can redifine it for your purposes
17
+ # public
18
+ # %w[ manage index create edit update ]
19
+ # %w[ my_comments my_draft my_published ]
20
+ # %w[ draft published deleted spam ]
21
+ # %w[ to_draft to_published to_deleted to_spam ]
22
+ # %w[ total_draft total_published total_deleted total_spam ]
23
+ #
24
+ #
25
+ # 2. Controller's private methods list:
26
+ # You can redifine it for your purposes
27
+ #
28
+ # private
29
+ # %w[ comment_template comment_partial ]
30
+ # %w[ denormalized_fields request_data_for_comment define_commentable ]
31
+ # %w[ comment_params patch_comment_params ]
32
+ # %w[ ajax_requests_required cookies_required ]
33
+ # %w[ empty_trap_required tolerance_time_required ]
34
+
35
+ # KAMINARI pagination:
36
+ # following methods based on gem "kaminari"
37
+ # You should redefine them if you use something else
38
+ #
39
+ # public
40
+ # %w[ manage index edit ]
41
+ # %w[ draft published deleted spam ]
42
+ # %w[ my_comments my_draft my_published ]
43
+ # %w[ total_draft total_published total_deleted total_spam ]
44
+ end
@@ -0,0 +1,197 @@
1
+ module TheComments
2
+ # Base functionality of Comments Controller
3
+ # class CommentsController < ApplicationController
4
+ # include TheComments::Controller
5
+ # end
6
+ module Controller
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include TheComments::ViewToken
11
+
12
+ # Attention! We should not set TheComments cookie before create
13
+ skip_before_action :set_the_comments_cookies, only: [:create]
14
+
15
+ # Spam protection
16
+ before_action -> { @errors = [] }, only: [:create]
17
+
18
+ before_action :ajax_requests_required, only: [:create]
19
+ before_action :cookies_required, only: [:create]
20
+
21
+ before_action :empty_trap_required, only: [:create], if: -> { TheComments.config.empty_trap_protection }
22
+ before_action :tolerance_time_required, only: [:create], if: -> { TheComments.config.tolerance_time_protection }
23
+
24
+ # preparation
25
+ before_action :define_commentable, only: [:create]
26
+
27
+ # raise an errors
28
+ before_action -> { return render(json: { errors: @errors }) unless @errors.blank? }, only: [:create]
29
+ end
30
+
31
+ # App side methods (you can overwrite them)
32
+
33
+ def manage
34
+ @comments = current_user.comcoms.with_users.active.recent.page(params[:page])
35
+ render comment_template(:manage)
36
+ end
37
+
38
+ def my_comments
39
+ @comments = current_user.my_comments.with_users.active.recent.page(params[:page])
40
+ render comment_template(:manage)
41
+ end
42
+
43
+ # Methods based on *current_user* helper
44
+ # Methods for admin
45
+ %w[draft published deleted].each do |state|
46
+ define_method "#{state}" do
47
+ @comments = current_user.comcoms.with_users.with_state(state).recent.page(params[:page])
48
+ render comment_template(:manage)
49
+ end
50
+
51
+ define_method "total_#{state}" do
52
+ @comments = ::Comment.with_state(state).with_users.recent.page(params[:page])
53
+ render comment_template(:manage)
54
+ end
55
+
56
+ define_method "my_#{state}" do
57
+ @comments = current_user.my_comments.with_users.with_state(state).recent.page(params[:page])
58
+ render comment_template(:manage)
59
+ end
60
+ end
61
+
62
+ def spam
63
+ @comments = current_user.comcoms.with_users.where(spam: true).recent.page(params[:page])
64
+ render comment_template(:manage)
65
+ end
66
+
67
+ def my_spam
68
+ @comments = current_user.my_comments.with_users.where(spam: true).recent.page(params[:page])
69
+ render comment_template(:manage)
70
+ end
71
+
72
+ def total_spam
73
+ @comments = ::Comment.where(spam: true).with_users.recent.page(params[:page])
74
+ render comment_template(:manage)
75
+ end
76
+
77
+ # BASE METHODS
78
+
79
+ # Public methods
80
+
81
+ def create
82
+ @comment = @commentable.comments.new comment_params
83
+ if @comment.valid?
84
+ @comment.save
85
+ return render layout: false, partial: comment_partial(:comment), locals: { tree: @comment }
86
+ end
87
+ render json: { errors: @comment.errors }
88
+ end
89
+
90
+ # Restricted area
91
+
92
+ def edit
93
+ @comments = current_user.comcoms.where(id: params[:id]).page(params[:page])
94
+ render comment_template(:manage)
95
+ end
96
+
97
+ def update
98
+ comment = ::Comment.find(params[:id])
99
+ comment.update_attributes!(patch_comment_params)
100
+ render(layout: false, partial: comment_partial(:comment_body), locals: { comment: comment })
101
+ end
102
+
103
+ %w[draft published deleted].each do |state|
104
+ define_method "to_#{state}" do
105
+ ::Comment.find(params[:id]).try "to_#{state}"
106
+ render nothing: true
107
+ end
108
+ end
109
+
110
+ def to_spam
111
+ comment = ::Comment.find(params[:id])
112
+ comment.to_spam
113
+ comment.to_deleted
114
+ render nothing: true
115
+ end
116
+
117
+ private
118
+
119
+ def comment_template template
120
+ { template: "the_comments/#{TheComments.config.template_engine}/#{template}" }
121
+ end
122
+
123
+ def comment_partial partial
124
+ "the_comments/#{TheComments.config.template_engine}/#{partial}"
125
+ end
126
+
127
+ def denormalized_fields
128
+ title = @commentable.commentable_title
129
+ url = @commentable.commentable_url
130
+ @commentable ? { commentable_title: title, commentable_url: url } : {}
131
+ end
132
+
133
+ def request_data_for_comment
134
+ r = request
135
+ { ip: r.ip, referer: CGI::unescape(r.referer || 'direct_visit'), user_agent: r.user_agent }
136
+ end
137
+
138
+ def define_commentable
139
+ commentable_klass = params[:comment][:commentable_type].constantize
140
+ commentable_id = params[:comment][:commentable_id]
141
+
142
+ @commentable = commentable_klass.find(commentable_id)
143
+ return render(json: { errors: [t('the_comments.undefined_commentable')] }) unless @commentable
144
+ end
145
+
146
+ def comment_params
147
+ params
148
+ .require(:comment)
149
+ .permit(:title, :contacts, :raw_content, :parent_id)
150
+ .merge(denormalized_fields)
151
+ .merge(request_data_for_comment)
152
+ .merge(tolerance_time: params[:tolerance_time].to_i)
153
+ .merge(user: current_user, view_token: comments_view_token)
154
+ end
155
+
156
+ def patch_comment_params
157
+ params
158
+ .require(:comment)
159
+ .permit(:title, :contacts, :raw_content, :parent_id)
160
+ end
161
+
162
+ # Protection hooks
163
+ def ajax_requests_required
164
+ unless request.xhr?
165
+ return render(text: t('the_comments.ajax_requests_required'))
166
+ end
167
+ end
168
+
169
+ def cookies_required
170
+ if cookies[:the_comment_cookies] != TheComments::COMMENTS_COOKIES_TOKEN
171
+ @errors << [t('the_comments.cookies'), t('the_comments.cookies_required')].join(': ')
172
+ end
173
+ end
174
+
175
+ # TODO:
176
+ # 1) inject ?
177
+ # 2) fields can be removed on client side
178
+ def empty_trap_required
179
+ is_human = true
180
+ params.slice(*TheComments.config.empty_inputs).values.each{|v| is_human = (is_human && v.blank?) }
181
+
182
+ if !is_human
183
+ @errors << [t('the_comments.trap'), t('the_comments.trap_message')].join(': ')
184
+ end
185
+ end
186
+
187
+ def tolerance_time_required
188
+ this_time = params[:tolerance_time].to_i
189
+ min_time = TheComments.config.tolerance_time.to_i
190
+
191
+ if this_time < min_time
192
+ tdiff = min_time - this_time
193
+ @errors << [t('the_comments.tolerance_time'), t('the_comments.tolerance_time_message', time: tdiff )].join(': ')
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,20 @@
1
+ module TheComments
2
+ # Cookies and View token for spam protection
3
+ # include TheComments::ViewToken
4
+ module ViewToken
5
+ extend ActiveSupport::Concern
6
+
7
+ included { before_action :set_the_comments_cookies }
8
+
9
+ def comments_view_token
10
+ cookies[:comments_view_token]
11
+ end
12
+
13
+ private
14
+
15
+ def set_the_comments_cookies
16
+ cookies[:the_comment_cookies] = { value: TheComments::COMMENTS_COOKIES_TOKEN, expires: 1.year.from_now }
17
+ cookies[:comments_view_token] = { value: SecureRandom.hex, expires: 7.days.from_now } unless cookies[:comments_view_token]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,111 @@
1
+ # coding: UTF-8
2
+ # DOC:
3
+ # We use Helper Methods for tree building,
4
+ # because it's faster than View Templates and Partials
5
+
6
+ # SECURITY note
7
+ # Prepare your data on server side for rendering
8
+ # or use h.html_escape(node.content)
9
+ # for escape potentially dangerous content
10
+ module RenderCommentsTreeHelper
11
+ module Render
12
+ class << self
13
+ attr_accessor :h, :options
14
+
15
+ # Main Helpers
16
+ def controller
17
+ @options[:controller]
18
+ end
19
+
20
+ def t str
21
+ controller.t str
22
+ end
23
+
24
+ # Render Helpers
25
+ def visible_draft?
26
+ controller.try(:comments_view_token) == @comment.view_token
27
+ end
28
+
29
+ def moderator?
30
+ controller.try(:current_user).try(:comments_moderator?, @comment)
31
+ end
32
+
33
+ # Render Methods
34
+ def render_node(h, options)
35
+ @h, @options = h, options
36
+ @comment = options[:node]
37
+
38
+ @max_reply_depth = options[:max_reply_depth] || TheComments.config.max_reply_depth
39
+
40
+ if @comment.draft?
41
+ draft_comment
42
+ else @comment.published?
43
+ published_comment
44
+ end
45
+ end
46
+
47
+ def draft_comment
48
+ if visible_draft? || moderator?
49
+ published_comment
50
+ else
51
+ "<li class='draft'>
52
+ <div class='comment draft' id='comment_#{@comment.anchor}'>
53
+ #{ t('the_comments.waiting_for_moderation') }
54
+ #{ h.link_to '#', '#comment_' + @comment.anchor }
55
+ </div>
56
+ #{ children }
57
+ </li>"
58
+ end
59
+ end
60
+
61
+ def published_comment
62
+ "<li>
63
+ <div id='comment_#{@comment.anchor}' class='comment #{@comment.state}' data-comment-id='#{@comment.to_param}'>
64
+ <div>
65
+ #{ avatar }
66
+ #{ userbar }
67
+ <div class='cbody'>#{ @comment.content }</div>
68
+ #{ reply }
69
+ </div>
70
+ </div>
71
+
72
+ <div class='form_holder'></div>
73
+ #{ children }
74
+ </li>"
75
+ end
76
+
77
+ def avatar
78
+ "<div class='userpic'>
79
+ <img src='#{ @comment.avatar_url }' alt='userpic' />
80
+ #{ controls }
81
+ </div>"
82
+ end
83
+
84
+ def userbar
85
+ anchor = h.link_to('#', '#comment_' + @comment.anchor)
86
+ title = @comment.title.blank? ? t('the_comments.guest_name') : @comment.title
87
+ "<div class='userbar'>#{ title } #{ anchor }</div>"
88
+ end
89
+
90
+ def moderator_controls
91
+ if moderator?
92
+ h.link_to(t('the_comments.edit'), h.edit_comment_url(@comment), class: :edit)
93
+ end
94
+ end
95
+
96
+ def reply
97
+ if @comment.depth < (@max_reply_depth - 1)
98
+ "<p class='reply'><a href='#' class='reply_link'>#{ t('the_comments.reply') }</a>"
99
+ end
100
+ end
101
+
102
+ def controls
103
+ "<div class='controls'>#{ moderator_controls }</div>"
104
+ end
105
+
106
+ def children
107
+ "<ol class='nested_set'>#{ options[:children] }</ol>"
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,38 @@
1
+ class Comment < ActiveRecord::Base
2
+ include TheComments::Comment
3
+ # ---------------------------------------------------
4
+ # Define comment's avatar url
5
+ # Usually we use Comment#user (owner of comment) to define avatar
6
+ # @blog.comments.includes(:user) <= use includes(:user) to decrease queries count
7
+ # comment#user.avatar_url
8
+ # ---------------------------------------------------
9
+
10
+ # public
11
+ # ---------------------------------------------------
12
+ # Simple way to define avatar url
13
+ #
14
+ # def avatar_url
15
+ # src = id.to_s
16
+ # src = title unless title.blank?
17
+ # src = contacts if !contacts.blank? && /@/ =~ contacts
18
+ # hash = Digest::MD5.hexdigest(src)
19
+ # "https://2.gravatar.com/avatar/#{hash}?s=42&d=https://identicons.github.com/#{hash}.png"
20
+ # end
21
+ # ---------------------------------------------------
22
+
23
+ # private
24
+ # ---------------------------------------------------
25
+ # Define your content filters
26
+ # gem 'RedCloth'
27
+ # gem 'sanitize'
28
+ # gem 'MySmilesProcessor'
29
+ #
30
+ # def prepare_content
31
+ # text = self.raw_content
32
+ # text = RedCloth.new(text).to_html
33
+ # text = MySmilesProcessor.new(text)
34
+ # text = Sanitize.clean(text, Sanitize::Config::RELAXED)
35
+ # self.content = text
36
+ # end
37
+ # ---------------------------------------------------
38
+ end