the_comments 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. data/.rvmrc.example +1 -0
  2. data/.travis.yml +5 -0
  3. data/README.md +105 -425
  4. data/app/assets/javascripts/the_comments.js.coffee +12 -9
  5. data/app/assets/javascripts/the_comments_manage.js.coffee +19 -49
  6. data/app/assets/stylesheets/the_comments.css.scss +20 -29
  7. data/app/controllers/_templates_/comments_controller.rb +44 -0
  8. data/app/controllers/concerns/controller.rb +216 -0
  9. data/app/helpers/render_comments_tree_helper.rb +4 -7
  10. data/app/models/_templates_/comment.rb +38 -0
  11. data/app/models/concerns/comment.rb +103 -0
  12. data/app/models/concerns/comment_states.rb +80 -0
  13. data/app/models/concerns/commentable.rb +69 -0
  14. data/app/models/concerns/user.rb +52 -0
  15. data/app/views/the_comments/_tree.html.erb +3 -0
  16. data/app/views/the_comments/haml/_additional_info.html.haml +13 -0
  17. data/app/views/the_comments/{_comment.html.haml → haml/_comment.html.haml} +0 -0
  18. data/app/views/the_comments/haml/_comment_body.html.haml +20 -0
  19. data/app/views/the_comments/haml/_comment_edit.html.haml +26 -0
  20. data/app/views/the_comments/{_form.html.haml → haml/_form.html.haml} +8 -6
  21. data/app/views/the_comments/haml/_manage_controls.html.haml +27 -0
  22. data/app/views/the_comments/haml/_sidebar.html.haml +28 -0
  23. data/app/views/the_comments/haml/_tree.html.haml +4 -0
  24. data/app/views/the_comments/haml/index.html.haml +18 -0
  25. data/app/views/the_comments/haml/manage.html.haml +25 -0
  26. data/app/views/the_comments/haml/my_comments.html.haml +28 -0
  27. data/app/views/the_comments/slim/_additional_info.html.slim +13 -0
  28. data/app/views/the_comments/slim/_comment.html.slim +1 -0
  29. data/app/views/the_comments/slim/_comment_body.html.slim +20 -0
  30. data/app/views/the_comments/slim/_comment_edit.html.slim +26 -0
  31. data/app/views/the_comments/slim/_form.html.slim +27 -0
  32. data/app/views/the_comments/slim/_manage_controls.html.slim +27 -0
  33. data/app/views/the_comments/slim/_sidebar.html.slim +28 -0
  34. data/app/views/the_comments/slim/_tree.html.slim +4 -0
  35. data/app/views/the_comments/slim/index.html.slim +18 -0
  36. data/app/views/the_comments/slim/manage.html.slim +25 -0
  37. data/app/views/the_comments/slim/my_comments.html.slim +28 -0
  38. data/{lib/generators/the_comments/templates → config/initializers}/the_comments.rb +3 -0
  39. data/config/locales/en.yml +39 -14
  40. data/config/locales/ru.yml +67 -0
  41. data/config/routes.rb +17 -13
  42. data/db/migrate/20130101010101_change_user.rb +18 -0
  43. data/db/migrate/20130101010102_create_comments.rb +50 -0
  44. data/db/migrate/20130101010103_change_commentable.rb +13 -0
  45. data/docs/admin_ui_installation.md +145 -0
  46. data/docs/advanced_installation.md +182 -0
  47. data/docs/comment_api.md +58 -0
  48. data/docs/commentable_api.md +59 -0
  49. data/docs/config_file.md +27 -0
  50. data/docs/content_preprocessors.md +73 -0
  51. data/docs/customazation_of_views.md +30 -0
  52. data/docs/denormalization_and_recent_comments.md +40 -0
  53. data/docs/documentation.md +28 -0
  54. data/docs/mountable_routes.md +80 -0
  55. data/docs/pagination.md +123 -0
  56. data/docs/screencast.jpg +0 -0
  57. data/docs/user_api.md +75 -0
  58. data/docs/what_is_comcoms.md +63 -0
  59. data/docs/whats_wrong_with_other_gems.md +18 -0
  60. data/docs/where_is_example_application.md +37 -0
  61. data/gem_version.rb +3 -0
  62. data/lib/generators/the_comments/USAGE +31 -20
  63. data/lib/generators/the_comments/the_comments_generator.rb +35 -18
  64. data/lib/generators/the_comments/views_generator.rb +52 -16
  65. data/lib/the_comments/config.rb +14 -1
  66. data/lib/the_comments/version.rb +1 -3
  67. data/lib/the_comments.rb +10 -0
  68. data/spec/dummy_app/.gitignore +17 -0
  69. data/spec/dummy_app/.rspec +1 -0
  70. data/spec/dummy_app/.ruby-gemset +1 -0
  71. data/spec/dummy_app/.ruby-version +1 -0
  72. data/spec/dummy_app/Gemfile +43 -0
  73. data/spec/dummy_app/README.md +50 -0
  74. data/spec/dummy_app/Rakefile +6 -0
  75. data/spec/dummy_app/app/assets/images/.keep +0 -0
  76. data/spec/dummy_app/app/assets/javascripts/admin_panel.js +5 -0
  77. data/spec/dummy_app/app/assets/javascripts/application.js +16 -0
  78. data/spec/dummy_app/app/assets/stylesheets/admin_panel.css +3 -0
  79. data/spec/dummy_app/app/assets/stylesheets/app.css.scss +4 -0
  80. data/spec/dummy_app/app/assets/stylesheets/application.css +16 -0
  81. data/spec/dummy_app/app/controllers/application_controller.rb +7 -0
  82. data/{lib/generators/the_comments/templates → spec/dummy_app/app/controllers}/comments_controller.rb +3 -1
  83. data/spec/dummy_app/app/controllers/concerns/.keep +0 -0
  84. data/spec/dummy_app/app/controllers/posts_controller.rb +13 -0
  85. data/spec/dummy_app/app/controllers/users_controller.rb +7 -0
  86. data/spec/dummy_app/app/helpers/application_helper.rb +2 -0
  87. data/spec/dummy_app/app/mailers/.keep +0 -0
  88. data/spec/dummy_app/app/models/.keep +0 -0
  89. data/spec/dummy_app/app/models/comment.rb +32 -0
  90. data/spec/dummy_app/app/models/concerns/.keep +0 -0
  91. data/spec/dummy_app/app/models/post.rb +17 -0
  92. data/spec/dummy_app/app/models/user.rb +21 -0
  93. data/spec/dummy_app/app/views/layouts/admin.html.haml +25 -0
  94. data/spec/dummy_app/app/views/layouts/application.html.haml +20 -0
  95. data/spec/dummy_app/app/views/posts/index.html.haml +22 -0
  96. data/spec/dummy_app/app/views/posts/show.html.haml +7 -0
  97. data/spec/dummy_app/bin/bundle +3 -0
  98. data/spec/dummy_app/bin/rails +4 -0
  99. data/spec/dummy_app/bin/rake +4 -0
  100. data/spec/dummy_app/config/application.rb +23 -0
  101. data/spec/dummy_app/config/boot.rb +4 -0
  102. data/spec/dummy_app/config/database.yml +11 -0
  103. data/spec/dummy_app/config/environment.rb +5 -0
  104. data/spec/dummy_app/config/environments/development.rb +29 -0
  105. data/spec/dummy_app/config/environments/production.rb +80 -0
  106. data/spec/dummy_app/config/environments/test.rb +36 -0
  107. data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  108. data/spec/dummy_app/config/initializers/filter_parameter_logging.rb +4 -0
  109. data/spec/dummy_app/config/initializers/inflections.rb +16 -0
  110. data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
  111. data/spec/dummy_app/config/initializers/secret_token.rb +12 -0
  112. data/spec/dummy_app/config/initializers/session_store.rb +3 -0
  113. data/spec/dummy_app/config/initializers/sorcery.rb +437 -0
  114. data/spec/dummy_app/config/initializers/the_comments.rb +13 -0
  115. data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
  116. data/spec/dummy_app/config/locales/en.yml +23 -0
  117. data/spec/dummy_app/config/routes.rb +15 -0
  118. data/spec/dummy_app/config.ru +4 -0
  119. data/spec/dummy_app/db/migrate/20130712061503_sorcery_core.rb +16 -0
  120. data/spec/dummy_app/db/migrate/20130712065951_create_posts.rb +11 -0
  121. data/spec/dummy_app/db/migrate/20131027185332_change_user.the_comments_engine.rb +19 -0
  122. data/spec/dummy_app/db/migrate/20131027185333_create_comments.the_comments_engine.rb +51 -0
  123. data/spec/dummy_app/db/migrate/20131027185334_change_commentable.the_comments_engine.rb +14 -0
  124. data/spec/dummy_app/db/schema.rb +74 -0
  125. data/spec/dummy_app/db/seeds.rb +42 -0
  126. data/spec/dummy_app/lib/assets/.keep +0 -0
  127. data/spec/dummy_app/lib/tasks/.keep +0 -0
  128. data/spec/dummy_app/lib/tasks/app_bootstrap.rake +15 -0
  129. data/spec/dummy_app/log/.keep +0 -0
  130. data/spec/dummy_app/public/404.html +58 -0
  131. data/spec/dummy_app/public/422.html +58 -0
  132. data/spec/dummy_app/public/500.html +57 -0
  133. data/spec/dummy_app/public/favicon.ico +0 -0
  134. data/spec/dummy_app/public/robots.txt +5 -0
  135. data/spec/dummy_app/spec/factories/post.rb +6 -0
  136. data/spec/dummy_app/spec/factories/user.rb +6 -0
  137. data/spec/dummy_app/spec/models/user_counters_spec.rb +339 -0
  138. data/spec/dummy_app/spec/spec_helper.rb +29 -0
  139. data/spec/dummy_app/test/controllers/.keep +0 -0
  140. data/spec/dummy_app/test/fixtures/.keep +0 -0
  141. data/spec/dummy_app/test/helpers/.keep +0 -0
  142. data/spec/dummy_app/test/integration/.keep +0 -0
  143. data/spec/dummy_app/test/mailers/.keep +0 -0
  144. data/spec/dummy_app/test/models/.keep +0 -0
  145. data/spec/dummy_app/test/test_helper.rb +15 -0
  146. data/spec/dummy_app/vendor/assets/javascripts/.keep +0 -0
  147. data/spec/dummy_app/vendor/assets/stylesheets/.keep +0 -0
  148. data/views_converter.rb +16 -0
  149. metadata +223 -45
  150. data/app/controllers/concerns/the_comments_controller.rb +0 -229
  151. data/app/controllers/concerns/the_comments_ip_controller.rb +0 -17
  152. data/app/controllers/concerns/the_comments_user_agent_controller.rb +0 -15
  153. data/app/models/concerns/the_comments_base.rb +0 -69
  154. data/app/models/concerns/the_comments_black_ip.rb +0 -9
  155. data/app/models/concerns/the_comments_black_user_agent.rb +0 -9
  156. data/app/models/concerns/the_comments_commentable.rb +0 -66
  157. data/app/models/concerns/the_comments_states.rb +0 -65
  158. data/app/models/concerns/the_comments_user.rb +0 -32
  159. data/app/views/ip_black_lists/index.html.haml +0 -17
  160. data/app/views/the_comments/_comment_body.html.haml +0 -30
  161. data/app/views/the_comments/_manage_controls.html.haml +0 -4
  162. data/app/views/the_comments/_tree.html.haml +0 -4
  163. data/app/views/the_comments/index.html.haml +0 -19
  164. data/app/views/the_comments/manage.html.haml +0 -29
  165. data/app/views/user_agent_black_lists/index.html.haml +0 -17
  166. data/db/migrate/20130101010101_create_comments.rb +0 -90
  167. data/lib/generators/the_comments/templates/ip_black_list.rb +0 -3
  168. data/lib/generators/the_comments/templates/ip_black_lists_controller.rb +0 -10
  169. data/lib/generators/the_comments/templates/the_comments_black_ip.rb +0 -9
  170. data/lib/generators/the_comments/templates/the_comments_black_user_agent.rb +0 -9
  171. data/lib/generators/the_comments/templates/user_agent_black_list.rb +0 -3
  172. data/lib/generators/the_comments/templates/user_agent_black_lists_controller.rb +0 -10
@@ -1,5 +1,5 @@
1
1
  # ERROR MSG BUILDER
2
- @error_text_builder = (errors) ->
2
+ @comments_errors_builder = (errors) ->
3
3
  error_msgs = ''
4
4
  for error in errors
5
5
  error_msgs += "<p><b>#{ error }</b></p>"
@@ -15,7 +15,7 @@
15
15
  @comments_error_notifier = (form, text) ->
16
16
  form.children('.error_notifier').empty().hide().append(text).show()
17
17
 
18
- # JUST HELPER
18
+ # TIME HELPER
19
19
  @unixsec = (t) -> Math.round(t.getTime() / 1000)
20
20
 
21
21
  # HIGHTLIGHT ANCHOR
@@ -26,12 +26,11 @@
26
26
 
27
27
  $ ->
28
28
  window.tolerance_time_start = unixsec(new Date)
29
-
30
- comment_forms = "#new_comment, .reply_comments_form"
31
29
  tolerance_time = $('[data-comments-tolarance-time]').first().data('comments-tolarance-time')
32
30
 
33
31
  # Button Click => AJAX Before Send
34
32
  submits = '#new_comment input[type=submit], .reply_comments_form input[type=submit]'
33
+
35
34
  $(document).on 'click', submits, (e) ->
36
35
  button = $ e.target
37
36
  form = button.parents('form').first()
@@ -39,7 +38,7 @@ $ ->
39
38
 
40
39
  if tolerance_time && (time_diff < tolerance_time)
41
40
  delta = tolerance_time - time_diff
42
- error_msgs = error_text_builder(["Please wait #{delta} secs"])
41
+ error_msgs = comments_errors_builder(["Please wait #{delta} secs"])
43
42
  comments_error_notifier(form, error_msgs)
44
43
  return false
45
44
 
@@ -47,14 +46,17 @@ $ ->
47
46
  button.hide()
48
47
  true
49
48
 
50
- # AJAX ERROR
49
+ ################ COMMENTS FORMS ################
50
+ comment_forms = "#new_comment, .reply_comments_form"
51
+
52
+ # ERROR
51
53
  $(document).on 'ajax:error', comment_forms, (request, response, status) ->
52
54
  form = $ @
53
55
  $('input[type=submit]', form).show()
54
- error_msgs = error_text_builder(["Server Error: #{response.status}"])
56
+ error_msgs = comments_errors_builder(["Server Error: #{response.status}"])
55
57
  comments_error_notifier(form, error_msgs)
56
58
 
57
- # COMMENT FORMS => SUCCESS
59
+ # SUCCESS
58
60
  $(document).on 'ajax:success', comment_forms, (request, response, status) ->
59
61
  form = $ @
60
62
  $('input[type=submit]', form).show()
@@ -70,7 +72,7 @@ $ ->
70
72
  tree.append(response)
71
73
  document.location.hash = anchor
72
74
  else
73
- error_msgs = error_text_builder(response.errors)
75
+ error_msgs = comments_errors_builder(response.errors)
74
76
  comments_error_notifier(form, error_msgs)
75
77
 
76
78
  # NEW ROOT BUTTON
@@ -92,6 +94,7 @@ $ ->
92
94
  $('.parent_id', form).val comment_id
93
95
 
94
96
  comment.siblings('.form_holder').html(form)
97
+ $('.error_notifier', form).empty().hide()
95
98
  form.fadeIn()
96
99
  false
97
100
 
@@ -1,57 +1,27 @@
1
1
  $ ->
2
- # CONTROLS
3
- holder = $('.comments_list')
4
-
5
- holder.on 'ajax:success', '.to_published', (request, response, status) ->
6
- link = $ @
7
- link.parents('.item').first().attr('class', 'item published')
8
-
9
- holder.on 'ajax:success', '.to_draft', (request, response, status) ->
10
- link = $ @
11
- link.parents('.item').first().attr('class', 'item draft')
12
-
13
- holder.on 'ajax:success', '.to_spam, .to_deleted', (request, response, status) ->
14
- $(@).parents('li').first().hide()
15
-
16
- $('.comments_tree').on 'ajax:success', '.delete', (request, response, status) ->
17
- $(@).parents('li').first().hide()
2
+ hide_comment_panel = (btn) -> $(btn).parents('.panel').slideUp()
18
3
 
19
- # INPLACE EDIT
20
- inplace_forms = '.comments_list .form form'
21
- $(document).on 'ajax:success', inplace_forms, (request, response, status) ->
22
- form = $ @
23
- item = form.parents('.item')
24
- item.children('.body').html(response).show()
25
- item.children('.form').hide()
4
+ comments = $ '.comments'
26
5
 
27
- # FOR MANAGE SECTION
28
- list = $('.comments_list')
29
-
30
- list.on 'click', '.controls a.view', ->
31
- form = $(@).parents('div.form')
32
- body = form.siblings('.body')
33
- body.show()
34
- form.hide()
6
+ # CONTROLS
7
+ comments.on 'click', 'a.additional_info', ->
8
+ btn = $ @
9
+ holder = btn.parents('.panel-body')
10
+ holder.find('div.additional_info').slideToggle()
35
11
  false
36
12
 
37
- list.on 'click', '.controls a.edit', ->
38
- body = $(@).parents('div.body')
39
- form = body.siblings('.form')
40
- body.hide()
41
- form.show()
13
+ comments.on 'click', 'a.edit', ->
14
+ btn = $ @
15
+ holder = btn.parents('.panel-body')
16
+ holder.find('.edit_form, .comment_body, a.edit').toggle()
42
17
  false
43
18
 
44
- # BLACK LIST
45
- holder = $('.black_list')
46
-
47
- holder.on 'ajax:success', '.to_warning', (request, response, status) ->
48
- link = $ @
49
- li = link.parents('li').first()
50
- li.attr 'class', 'warning'
51
- li.find('.state').html 'warning'
19
+ comments.on 'ajax:success', '.to_published, .to_draft, .to_spam, .to_deleted', ->
20
+ hide_comment_panel @
52
21
 
53
- holder.on 'ajax:success', '.to_banned', (request, response, status) ->
54
- link = $ @
55
- li = link.parents('li').first()
56
- li.attr 'class', 'banned'
57
- li.find('.state').html 'banned'
22
+ # Edit form
23
+ comments.on 'ajax:success', '.edit_comment', (request, response, status) ->
24
+ form = $ @
25
+ holder = form.parents('.panel-body')
26
+ holder.find('.edit_form, .comment_body, a.edit').toggle()
27
+ holder.find('.comment_body').replaceWith response
@@ -1,8 +1,11 @@
1
- .comments_tree, .comments_list, .black_list{
1
+ .comments_tree, .comments_list{
2
2
  font-family: Arial;
3
3
 
4
- margin:0; padding:0;
5
- *{ margin: 0; padding: 0; }
4
+ margin:0;
5
+ padding:0;
6
+ margin-bottom: 30px;
7
+
8
+ *{ margin: 0; padding: 0; font-size: inherit; }
6
9
 
7
10
  a{ text-decoration: none; }
8
11
  a:hover{ text-decoration: underline; }
@@ -23,9 +26,11 @@
23
26
  font-family: Arial;
24
27
  font-size: 13px;
25
28
 
29
+ h3{ font-size: 1.6em; }
30
+
26
31
  .error_notifier{
27
32
  background-color: #F2DEDE;
28
- border-color: #EED3D7;
33
+ border: 1px solid #B94A48;
29
34
  color: #B94A48;
30
35
 
31
36
  border-radius: 4px;
@@ -36,9 +41,11 @@
36
41
  p{ margin: 0 0 10px 0; }
37
42
  }
38
43
  form{
39
- background: white;
40
- border: 1px solid gray;
41
- border-radius: 3px;
44
+
45
+ background: #e0e4f5;
46
+
47
+ border: 1px solid #c6cff5;
48
+ border-radius: 5px;
42
49
  padding: 10px;
43
50
 
44
51
  p{ margin: 0 0 10px 0; }
@@ -48,6 +55,7 @@
48
55
  padding: 4px;
49
56
  width: 75%;
50
57
  }
58
+ label{ font-size: 15px; }
51
59
  textarea{
52
60
  border: 1px solid gray;
53
61
  font-family: Arial;
@@ -99,7 +107,7 @@
99
107
  float: left;
100
108
  width: 50px;
101
109
 
102
- img{ margin-bottom: 10px; }
110
+ img{ margin-bottom: 10px; width: 42px; height: 42px; }
103
111
  }
104
112
  .userbar, .cbody{
105
113
  margin: 0 0 5px 55px;
@@ -118,10 +126,12 @@
118
126
  .to_published{ display: none; }
119
127
  }
120
128
  .cbody{
121
- border-bottom: 1px solid LightGray;
129
+ font-size: 15px;
130
+ border-bottom: 1px solid #eee;
122
131
  padding-bottom: 10px;
123
132
  line-height: 135%;
124
- margin-bottom: 0;
133
+ margin-bottom: 3px;
134
+ overflow: hidden;
125
135
  }
126
136
  .reply{
127
137
  margin: 0 0 5px 55px;
@@ -230,23 +240,4 @@
230
240
  }
231
241
  }
232
242
  }
233
- }
234
-
235
- .black_list{
236
- li{
237
- border: 1px solid gray;
238
- border-radius: 5px;
239
- padding: 10px;
240
- &.warning{
241
- border-left: 5px solid orange;
242
- .to_warning{ display: none; }
243
- }
244
- &.banned{
245
- border-left: 5px solid black;
246
- .to_banned{ display: none; }
247
- }
248
- }
249
- p{
250
- margin-bottom: 10px;
251
- }
252
243
  }
@@ -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,216 @@
1
+ module TheComments
2
+ COMMENTS_COOKIES_TOKEN = 'JustTheCommentsCookies'
3
+
4
+ # Cookies and View token for spam protection
5
+ # include TheComments::ViewToken
6
+ module ViewToken
7
+ extend ActiveSupport::Concern
8
+
9
+ included { before_action :set_the_comments_cookies }
10
+
11
+ def comments_view_token
12
+ cookies[:comments_view_token]
13
+ end
14
+
15
+ private
16
+
17
+ def set_the_comments_cookies
18
+ cookies[:the_comment_cookies] = { value: TheComments::COMMENTS_COOKIES_TOKEN, expires: 1.year.from_now }
19
+ cookies[:comments_view_token] = { value: SecureRandom.hex, expires: 7.days.from_now } unless cookies[:comments_view_token]
20
+ end
21
+ end
22
+
23
+ # Base functionality of Comments Controller
24
+ # class CommentsController < ApplicationController
25
+ # include TheComments::Controller
26
+ # end
27
+ module Controller
28
+ extend ActiveSupport::Concern
29
+
30
+ included do
31
+ include TheComments::ViewToken
32
+
33
+ # Attention! We should not set TheComments cookie before create
34
+ skip_before_action :set_the_comments_cookies, only: [:create]
35
+
36
+ # Spam protection
37
+ before_action -> { @errors = [] }, only: [:create]
38
+
39
+ before_action :ajax_requests_required, only: [:create]
40
+ before_action :cookies_required, only: [:create]
41
+
42
+ before_action :empty_trap_required, only: [:create], if: -> { TheComments.config.empty_trap_protection }
43
+ before_action :tolerance_time_required, only: [:create], if: -> { TheComments.config.tolerance_time_protection }
44
+
45
+ # preparation
46
+ before_action :define_commentable, only: [:create]
47
+
48
+ # raise an errors
49
+ before_action -> { return render(json: { errors: @errors }) unless @errors.blank? }, only: [:create]
50
+ end
51
+
52
+ # App side methods (you can overwrite them)
53
+ def index
54
+ @comments = ::Comment.with_state(:published).recent.page(params[:page])
55
+ render comment_template(:index)
56
+ end
57
+
58
+ def manage
59
+ @comments = current_user.comcoms.active.recent.page(params[:page])
60
+ render comment_template(:manage)
61
+ end
62
+
63
+ def my_comments
64
+ @comments = current_user.my_comments.active.recent.page(params[:page])
65
+ render comment_template(:my_comments)
66
+ end
67
+
68
+ def edit
69
+ @comments = current_user.comcoms.where(id: params[:id]).page(params[:page])
70
+ render comment_template(:manage)
71
+ end
72
+
73
+ # Methods based on *current_user* helper
74
+ # Methods for admin
75
+ %w[draft published deleted].each do |state|
76
+ define_method "#{state}" do
77
+ @comments = current_user.comcoms.with_state(state).recent.page(params[:page])
78
+ render comment_template(:manage)
79
+ end
80
+
81
+ define_method "total_#{state}" do
82
+ @comments = ::Comment.with_state(state).recent.page(params[:page])
83
+ render comment_template(:manage)
84
+ end
85
+
86
+ unless state == 'deleted'
87
+ define_method "my_#{state}" do
88
+ @comments = current_user.my_comments.with_state(state).recent.page(params[:page])
89
+ render comment_template(:my_comments)
90
+ end
91
+ end
92
+ end
93
+
94
+ def spam
95
+ @comments = current_user.comcoms.where(spam: true).recent.page(params[:page])
96
+ render comment_template(:manage)
97
+ end
98
+
99
+ def total_spam
100
+ @comments = ::Comment.where(spam: true).recent.page(params[:page])
101
+ render comment_template(:manage)
102
+ end
103
+
104
+ # BASE METHODS
105
+ # Public methods
106
+ def update
107
+ comment = ::Comment.find(params[:id])
108
+ comment.update_attributes!(patch_comment_params)
109
+ render(layout: false, partial: comment_partial(:comment_body), locals: { comment: comment })
110
+ end
111
+
112
+ def create
113
+ @comment = @commentable.comments.new comment_params
114
+ if @comment.valid?
115
+ @comment.save
116
+ return render layout: false, partial: comment_partial(:comment), locals: { tree: @comment }
117
+ end
118
+ render json: { errors: @comment.errors.full_messages }
119
+ end
120
+
121
+ # Restricted area
122
+ %w[draft published deleted].each do |state|
123
+ define_method "to_#{state}" do
124
+ ::Comment.find(params[:id]).try "to_#{state}"
125
+ render nothing: true
126
+ end
127
+ end
128
+
129
+ def to_spam
130
+ comment = ::Comment.find(params[:id])
131
+ comment.to_spam
132
+ comment.to_deleted
133
+ render nothing: true
134
+ end
135
+
136
+ private
137
+
138
+ def comment_template template
139
+ { template: "the_comments/#{TheComments.config.template_engine}/#{template}" }
140
+ end
141
+
142
+ def comment_partial partial
143
+ "the_comments/#{TheComments.config.template_engine}/#{partial}"
144
+ end
145
+
146
+ def denormalized_fields
147
+ title = @commentable.commentable_title
148
+ url = @commentable.commentable_url
149
+ @commentable ? { commentable_title: title, commentable_url: url } : {}
150
+ end
151
+
152
+ def request_data_for_comment
153
+ r = request
154
+ { ip: r.ip, referer: CGI::unescape(r.referer || 'direct_visit'), user_agent: r.user_agent }
155
+ end
156
+
157
+ def define_commentable
158
+ commentable_klass = params[:comment][:commentable_type].constantize
159
+ commentable_id = params[:comment][:commentable_id]
160
+
161
+ @commentable = commentable_klass.find(commentable_id)
162
+ return render(json: { errors: [t('the_comments.undefined_commentable')] }) unless @commentable
163
+ end
164
+
165
+ def comment_params
166
+ params
167
+ .require(:comment)
168
+ .permit(:title, :contacts, :raw_content, :parent_id)
169
+ .merge(denormalized_fields)
170
+ .merge(request_data_for_comment)
171
+ .merge(tolerance_time: params[:tolerance_time].to_i)
172
+ .merge(user: current_user, view_token: comments_view_token)
173
+ end
174
+
175
+ def patch_comment_params
176
+ params
177
+ .require(:comment)
178
+ .permit(:title, :contacts, :raw_content, :parent_id)
179
+ end
180
+
181
+ # Protection hooks
182
+ def ajax_requests_required
183
+ unless request.xhr?
184
+ return render(text: t('the_comments.ajax_requests_required'))
185
+ end
186
+ end
187
+
188
+ def cookies_required
189
+ if cookies[:the_comment_cookies] != TheComments::COMMENTS_COOKIES_TOKEN
190
+ @errors << [t('the_comments.cookies'), t('the_comments.cookies_required')].join(': ')
191
+ end
192
+ end
193
+
194
+ # TODO:
195
+ # 1) inject ?
196
+ # 2) fields can be removed on client side
197
+ def empty_trap_required
198
+ is_human = true
199
+ params.slice(*TheComments.config.empty_inputs).values.each{|v| is_human = (is_human && v.blank?) }
200
+
201
+ if !is_human
202
+ @errors << [t('the_comments.trap'), t('the_comments.trap_message')].join(': ')
203
+ end
204
+ end
205
+
206
+ def tolerance_time_required
207
+ this_time = params[:tolerance_time].to_i
208
+ min_time = TheComments.config.tolerance_time.to_i
209
+
210
+ if this_time < min_time
211
+ tdiff = min_time - this_time
212
+ @errors << [t('the_comments.tolerance_time'), t('the_comments.tolerance_time_message', time: tdiff )].join(': ')
213
+ end
214
+ end
215
+ end
216
+ end
@@ -27,7 +27,7 @@ module RenderCommentsTreeHelper
27
27
  end
28
28
 
29
29
  def moderator?
30
- controller.try(:current_user).try(:comment_moderator?, @comment)
30
+ controller.try(:current_user).try(:comments_moderator?, @comment)
31
31
  end
32
32
 
33
33
  # Render Methods
@@ -87,17 +87,14 @@ module RenderCommentsTreeHelper
87
87
  "<div class='userbar'>#{ title } #{ anchor }</div>"
88
88
  end
89
89
 
90
- def moderator_controls
91
- t = ''
90
+ def moderator_controls
92
91
  if moderator?
93
- t += h.link_to(t('the_comments.edit'), h.edit_comment_url(@comment), class: :edit)
94
- t += h.link_to(t('the_comments.to_deleted'), h.to_trash_comment_url(@comment), class: :delete, method: :delete, remote: true, confirm: t('the_comments.delete_confirm'))
92
+ h.link_to(t('the_comments.edit'), h.comments.edit_comment_url(@comment), class: :edit)
95
93
  end
96
- t
97
94
  end
98
95
 
99
96
  def reply
100
- if @comment.depth < @max_reply_depth
97
+ if @comment.depth < (@max_reply_depth - 1)
101
98
  "<p class='reply'><a href='#' class='reply_link'>#{ t('the_comments.reply') }</a>"
102
99
  end
103
100
  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
@@ -0,0 +1,103 @@
1
+ module TheComments
2
+ module Comment
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :active, -> { with_state [:draft, :published] }
7
+ scope :recent, -> { order('created_at DESC') }
8
+
9
+ # Nested Set
10
+ acts_as_nested_set scope: [:commentable_type, :commentable_id]
11
+
12
+ # Comments State Machine
13
+ include TheComments::CommentStates
14
+
15
+ # TheSortableTree
16
+ include TheSortableTree::Scopes
17
+
18
+ validates :raw_content, presence: true
19
+
20
+ # relations
21
+ belongs_to :user
22
+ belongs_to :holder, class_name: :User
23
+ belongs_to :commentable, polymorphic: true
24
+
25
+ # callbacks
26
+ before_create :define_holder, :define_default_state, :define_anchor, :denormalize_commentable
27
+ after_create :update_cache_counters
28
+ before_save :prepare_content
29
+ end
30
+
31
+ def avatar_url
32
+ src = id.to_s
33
+ src = title unless title.blank?
34
+ src = contacts if !contacts.blank? && /@/ =~ contacts
35
+ hash = Digest::MD5.hexdigest(src)
36
+ "https://2.gravatar.com/avatar/#{hash}?s=42&d=https://identicons.github.com/#{hash}.png"
37
+ end
38
+
39
+ def mark_as_spam
40
+ count = self_and_descendants.update_all({spam: true})
41
+ update_spam_counter
42
+ count
43
+ end
44
+
45
+ def mark_as_not_spam
46
+ count = self_and_descendants.update_all({spam: false})
47
+ update_spam_counter
48
+ count
49
+ end
50
+
51
+ def to_spam
52
+ mark_as_spam
53
+ end
54
+
55
+ private
56
+
57
+ def update_spam_counter
58
+ holder.try :update_comcoms_spam_counter
59
+ end
60
+
61
+ def define_anchor
62
+ self.anchor = SecureRandom.hex[0..5]
63
+ end
64
+
65
+ def define_holder
66
+ c = self.commentable
67
+ self.holder = c.is_a?(User) ? c : c.try(:user)
68
+ end
69
+
70
+ def define_default_state
71
+ self.state = TheComments.config.default_owner_state if user && user == holder
72
+ end
73
+
74
+ def denormalize_commentable
75
+ self.commentable_title = commentable.try :commentable_title
76
+ self.commentable_state = commentable.try :commentable_state
77
+ self.commentable_url = commentable.try :commentable_url
78
+ end
79
+
80
+ def prepare_content
81
+ self.content = self.raw_content
82
+ end
83
+
84
+ # Warn: increment! doesn't call validation =>
85
+ # before_validation filters doesn't work =>
86
+ # We have few unuseful requests
87
+ # I impressed that I found it and reduce DB requests
88
+ # Awesome logic pazzl! I'm really pedant :D
89
+ def update_cache_counters
90
+ user.try :recalculate_my_comments_counter!
91
+
92
+ if holder
93
+ holder.send :try, :define_denormalize_flags
94
+ holder.increment! "#{state}_comcoms_count"
95
+ end
96
+
97
+ if commentable
98
+ commentable.send :define_denormalize_flags
99
+ commentable.increment! "#{state}_comments_count"
100
+ end
101
+ end
102
+ end
103
+ end