biovision-comment 0.8.190926.0 → 0.12.200627.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/biovision/comment/comments.scss +11 -0
  3. data/app/controllers/admin/comments_controller.rb +3 -2
  4. data/app/controllers/comments_controller.rb +13 -7
  5. data/app/helpers/comments_helper.rb +2 -1
  6. data/app/mailers/comment_mailer.rb +20 -2
  7. data/app/models/comment.rb +23 -6
  8. data/app/models/concerns/commentable_item.rb +1 -1
  9. data/app/services/biovision/components/comments_component.rb +80 -9
  10. data/app/services/comment_handler.rb +1 -2
  11. data/app/views/admin/comments/entity/_in_list.html.erb +3 -3
  12. data/app/views/admin/comments/show.html.erb +1 -1
  13. data/app/views/comment_mailer/comment_reply.html.erb +18 -0
  14. data/app/views/comment_mailer/entry_reply.html.erb +18 -0
  15. data/app/views/comments/_comment.html.erb +7 -0
  16. data/app/views/comments/_form.html.erb +6 -2
  17. data/config/locales/comments-ru.yml +13 -2
  18. data/db/{migrate → amends}/20190203090909_add_fields_to_comments.rb +0 -0
  19. data/db/{migrate → amends}/20190428212121_add_approved_to_comments.rb +0 -0
  20. data/db/{migrate → amends}/20190428212122_create_comments_component.rb +4 -2
  21. data/db/{migrate → amends}/20190628101010_add_data_to_comments.rb +0 -0
  22. data/db/migrate/20170914000001_create_comments.rb +15 -5
  23. data/db/migrate/20191017202020_add_search_index_to_comments.rb +16 -0
  24. data/db/migrate/20200208090909_convert_comments_vote_data.rb +27 -0
  25. data/lib/biovision/comment/version.rb +1 -1
  26. metadata +11 -51
  27. data/app/services/comments_manager.rb +0 -16
  28. data/app/views/comment_mailer/entry_reply.text.erb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7aa9177ba4ca81f53183269587c9ff8d1ab7da046904e65616a72686856b1b44
4
- data.tar.gz: 24550aecb8c28841f760bbe9f4caef9ca502efb0c396450ab39f5a18f2499856
3
+ metadata.gz: fcfc0b5b350911016a52aca91b97a22d97fcb9b56db8f9eb9c896461b44bfb4f
4
+ data.tar.gz: 7fa54e4a1fdab7e2af536625e4997cfa5b8af28d50857193cb09dbd6757014e3
5
5
  SHA512:
6
- metadata.gz: b49ee2521b7c018184f042c464d905c6209452f21aacdb636327a4a07fe254ea79a34ff522ff7257531727e441076e8faf4f683fb8c3e235291904d58c7e8134
7
- data.tar.gz: 967b2cb830a8f4076c45c4ccdac61152f88943e67e0a3b5d13c642241e896bd6464c55f017f48884a5e7e4327214ceaa879a4d7cdda6dab94c06f297272370f2
6
+ metadata.gz: 28ea2988dac507f37e3b434944e73ac81ad4b66277b15b4e15a7b8c6a81b50a4c56d4beeef240baa7cf707e1bf09bcb43b8e3dc02deb3d0ab0205982daa2cd3c
7
+ data.tar.gz: 9aa0e6476f9b048c132f5ba7232918b9e9fc990578b75557a6a0beda636fc46724dfd56220dc7300bbec44a176ed9e98769de96ea721e38b765ce1bb3733f162
@@ -82,6 +82,7 @@ $row-background-odd: #fafafa !default;
82
82
 
83
83
  .comment-wrapper {
84
84
  display: flex;
85
+ flex-wrap: wrap;
85
86
  }
86
87
 
87
88
  .vote-block {
@@ -152,6 +153,16 @@ $row-background-odd: #fafafa !default;
152
153
  .children {
153
154
  margin-left: var(--spacer-xs, .8rem);
154
155
  }
156
+
157
+ .approval-buttons {
158
+ padding: var(--spacer-xs);
159
+ text-align: center;
160
+ width: 100%;
161
+
162
+ button {
163
+ cursor: pointer;
164
+ }
165
+ }
155
166
  }
156
167
 
157
168
  .comment-form {
@@ -19,6 +19,7 @@ class Admin::CommentsController < AdminController
19
19
  # put /admin/comments/:id/approve
20
20
  def approve
21
21
  @entity.update(approved: true)
22
+ component_handler.class.notify(@entity)
22
23
 
23
24
  head :no_content
24
25
  end
@@ -31,8 +32,8 @@ class Admin::CommentsController < AdminController
31
32
 
32
33
  protected
33
34
 
34
- def component_slug
35
- Biovision::Components::CommentsComponent::SLUG
35
+ def component_class
36
+ Biovision::Components::CommentsComponent
36
37
  end
37
38
 
38
39
  def restrict_access
@@ -51,8 +51,8 @@ class CommentsController < ApplicationController
51
51
 
52
52
  private
53
53
 
54
- def component_slug
55
- Biovision::Components::CommentsComponent::SLUG
54
+ def component_class
55
+ Biovision::Components::CommentsComponent
56
56
  end
57
57
 
58
58
  def restrict_access
@@ -65,9 +65,11 @@ class CommentsController < ApplicationController
65
65
  end
66
66
 
67
67
  def create_comment
68
- @entity = component_handler.create_comment(creation_parameters)
68
+ verify_captcha_and_create
69
69
  if @entity.valid?
70
- notify_participants
70
+ unless @entity.approved?
71
+ flash[:notice] = t('comments.create.premoderation')
72
+ end
71
73
  next_page = param_from_request(:return_url)
72
74
  form_processed_ok(next_page.match?(%r{\A/[^/]}) ? next_page : root_path)
73
75
  else
@@ -89,8 +91,12 @@ class CommentsController < ApplicationController
89
91
  params.require(:comment).permit(permitted).merge(owner_for_entity(true))
90
92
  end
91
93
 
92
- def notify_participants
93
- flash[:notice] = t('comments.create.premoderation') unless @entity.approved?
94
- # to be implemented...
94
+ protected
95
+
96
+ def verify_captcha_and_create
97
+ entity = Comment.new(creation_parameters)
98
+ verify_recaptcha(model: entity) if component_handler.use_captcha?
99
+
100
+ @entity = component_handler.create_comment(entity)
95
101
  end
96
102
  end
@@ -15,6 +15,7 @@ module CommentsHelper
15
15
  def comment_link(entity, text = entity.commentable_name, options = {})
16
16
  anchor = options.key?(:anchor)
17
17
  options.delete(:anchor)
18
- link_to(text, CommentsManager.commentable_path(entity, anchor), options)
18
+ path = Biovision::Components::CommentsComponent.commentable_path(entity, anchor)
19
+ link_to(text, path, options)
19
20
  end
20
21
  end
@@ -1,8 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Mailer for sending comment notifications
1
4
  class CommentMailer < ApplicationMailer
2
- # @param [Integer] comment
5
+ # @param [Integer] comment_id
3
6
  def entry_reply(comment_id)
4
7
  @comment = Comment.find_by(id: comment_id)
5
8
 
6
- mail to: @comment.commentable.user.email unless @comment.nil?
9
+ return if @comment.nil?
10
+
11
+ user = @comment.commentable.user
12
+
13
+ mail(to: user.email) if user.can_receive_letters?
14
+ end
15
+
16
+ # @param [Integer] comment_id
17
+ def comment_reply(comment_id)
18
+ @comment = Comment.find_by(id: comment_id)
19
+
20
+ return if @comment.nil?
21
+
22
+ user = @comment.parent.user
23
+
24
+ mail(to: user.email) if user.can_receive_letters?
7
25
  end
8
26
  end
@@ -11,6 +11,7 @@
11
11
  # commentable_id [Integer]
12
12
  # commentable_type [String]
13
13
  # created_at [DateTime]
14
+ # data [JSON]
14
15
  # deleted [Boolean]
15
16
  # downvote_count [Integer]
16
17
  # ip [Inet], optional
@@ -50,6 +51,7 @@ class Comment < ApplicationRecord
50
51
  scope :chronological, -> { order 'id asc' }
51
52
  scope :approved, -> { where(approved: true) }
52
53
  scope :visible, -> { approved.where(deleted: false, visible: true, spam: false) }
54
+ scope :search, ->(q) { where("to_tsvector('russian', body) @@ phraseto_tsquery('russian', ?)", q.to_s) unless q.blank? }
53
55
  scope :list_for_administration, -> { recent }
54
56
  scope :list_for_visitors, -> { visible.chronological }
55
57
  scope :list_for_visitors_recent, -> { visible.recent }
@@ -110,12 +112,18 @@ class Comment < ApplicationRecord
110
112
  end
111
113
 
112
114
  def notify_entry_owner?
115
+ return false unless commentable.respond_to?(:user)
116
+
113
117
  entry_owner = commentable.user
114
- if entry_owner.is_a?(User) && !owned_by?(entry_owner)
115
- entry_owner.can_receive_letters?
116
- else
117
- false
118
- end
118
+ return false if entry_owner.nil? || owned_by?(entry_owner)
119
+
120
+ !entry_owner.nil?
121
+ end
122
+
123
+ def notify_parent_owner?
124
+ return false if parent.nil?
125
+
126
+ !parent.owned_by?(user)
119
127
  end
120
128
 
121
129
  def text_for_link
@@ -127,7 +135,9 @@ class Comment < ApplicationRecord
127
135
  end
128
136
 
129
137
  def commentable_title
130
- if commentable.respond_to?(:title)
138
+ if commentable.respond_to?(:title!)
139
+ commentable.title!
140
+ elsif commentable.respond_to?(:title)
131
141
  commentable.title
132
142
  else
133
143
  commentable_name
@@ -138,6 +148,13 @@ class Comment < ApplicationRecord
138
148
  user.nil? ? author_name : user.profile_name
139
149
  end
140
150
 
151
+ # @param [Integer] word_count
152
+ def preview(word_count = 50)
153
+ words = body.split(/\s+/)
154
+ ellipsis = words.count > word_count ? '…' : ''
155
+ words.first(word_count).join(' ') + ellipsis
156
+ end
157
+
141
158
  private
142
159
 
143
160
  def commentable_is_commentable
@@ -10,6 +10,6 @@ module CommentableItem
10
10
 
11
11
  # @param [User] user
12
12
  def commentable_by?(user)
13
- !user.nil?
13
+ respond_to?(:visible_to?) ? visible_to?(user) : !user.nil?
14
14
  end
15
15
  end
@@ -10,28 +10,73 @@ module Biovision
10
10
  %w[moderator]
11
11
  end
12
12
 
13
+ # @param [Comment] comment
14
+ # @param [TrueClass|FalseClass] anchor
15
+ def self.commentable_path(comment, anchor = false)
16
+ method_name = "#{comment.commentable_type}_path".downcase.to_sym
17
+ if comment.commentable.respond_to?(:url)
18
+ result = comment.commentable.url
19
+ anchor ? "#{result}#comment-#{comment.id}" : result
20
+ else
21
+ "##{method_name}"
22
+ end
23
+ end
24
+
25
+ # @param [Comment] comment
26
+ def self.notify(comment)
27
+ return if comment.data['notified']
28
+
29
+ if comment.parent.nil?
30
+ if comment.notify_entry_owner?
31
+ CommentMailer.entry_reply(comment.id).deliver_later
32
+ end
33
+ elsif comment.notify_parent_owner?
34
+ CommentMailer.comment_reply(comment.id).deliver_later
35
+ end
36
+
37
+ comment.data['notified'] = true
38
+ comment.save
39
+ end
40
+
13
41
  def use_parameters?
14
42
  false
15
43
  end
16
44
 
17
- # @param [Hash] parameters
18
- def create_comment(parameters)
19
- @comment = ::Comment.new(parameters)
45
+ # @param [Hash|Comment] data
46
+ def create_comment(data)
47
+ @comment = data.is_a?(::Comment) ? data : ::Comment.new(data)
48
+ limit_comment_body
20
49
  @comment.approved = approval_flag if settings['premoderation']
21
- @comment.save
50
+ trap_spam if settings['trap_spam']
51
+ @comment.save unless ignore?
52
+ self.class.notify(@comment) if @comment.approved?
53
+
22
54
  @comment
23
55
  end
24
56
 
57
+ def use_captcha?
58
+ return false unless settings['recaptcha']
59
+ return false unless Gem.loaded_specs.key?('recaptcha')
60
+ return true if user.nil?
61
+
62
+ gate = settings['auto_approve_threshold'].to_i
63
+ positive = ::Comment.where(user: user, approved: true).count
64
+ negative = ::Comment.where(user: user, approved: false).count
65
+ positive - negative < gate
66
+ end
67
+
25
68
  protected
26
69
 
27
70
  # @param [Hash] data
28
71
  # @return [Hash]
29
72
  def normalize_settings(data)
30
73
  result = {}
31
- flags = %w[premoderation]
74
+ flags = %w[premoderation trap_spam recaptcha ignore_spam]
32
75
  flags.each { |f| result[f] = data[f].to_i == 1 }
33
- numbers = %w[auto_approve_threshold]
76
+ numbers = %w[auto_approve_threshold body_limit spam_link_threshold]
34
77
  numbers.each { |f| result[f] = data[f].to_i }
78
+ strings = %w[spam_pattern]
79
+ strings.each { |f| result[f] = data[f].to_s }
35
80
 
36
81
  result
37
82
  end
@@ -40,15 +85,41 @@ module Biovision
40
85
  threshold = settings['auto_approve_threshold']
41
86
  if @comment.user.nil?
42
87
  criteria = {
43
- user_id: nil,
44
- ip: @comment.ip,
45
- agent_id: @comment.agent_id
88
+ agent_id: @comment.agent_id, ip: @comment.ip, user_id: nil
46
89
  }
47
90
  ::Comment.approved.where(criteria).count >= threshold
48
91
  else
49
92
  ::Comment.approved.owned_by(@comment.user).count >= threshold
50
93
  end
51
94
  end
95
+
96
+ def trap_spam
97
+ @comment.approved = !spam?
98
+ end
99
+
100
+ def spam?
101
+ pattern = settings['spam_pattern']
102
+ return false if pattern.blank?
103
+
104
+ threshold = settings['spam_link_threshold'].to_i
105
+
106
+ @comment.body.scan(Regexp.new(pattern, 'i')).length > threshold
107
+ rescue RegexpError => e
108
+ Rails.logger.warn(e)
109
+ false
110
+ end
111
+
112
+ def ignore?
113
+ settings['ignore_spam'] && spam?
114
+ end
115
+
116
+ def limit_comment_body
117
+ body_limit = @component.settings['body_limit'].to_i
118
+ body_limit = 5000 if body_limit < 1
119
+ body_limit -= 1
120
+
121
+ @comment.body = @comment.body.to_s[0..body_limit]
122
+ end
52
123
  end
53
124
  end
54
125
  end
@@ -6,9 +6,8 @@ class CommentHandler
6
6
 
7
7
  # @param [User] user
8
8
  def initialize(user = nil)
9
- slug = Biovision::Components::CommentsComponent::SLUG
10
9
  @user = user
11
- @handler = Biovision::Components::BaseComponent.handler(slug, user)
10
+ @handler = Biovision::Components::CommentsComponent[user]
12
11
  end
13
12
 
14
13
  # Get list of comments for entity
@@ -12,13 +12,13 @@
12
12
 
13
13
  <div class="info">
14
14
  <%= entity.commentable_name %>
15
- (<%= entity.commentable_title %>)<br/>
15
+ (<cite><%= entity.commentable_title %></cite>)<br/>
16
16
  <%= admin_user_link(entity.user) %>,
17
17
  <%= time_tag entity.created_at %>
18
18
  </div>
19
19
 
20
20
  <div class="secondary info">
21
- <%= simple_format(entity.body) %>
21
+ <p><%= entity.preview %></p>
22
22
  </div>
23
23
 
24
24
  <% unless entity.approved? %>
@@ -31,7 +31,7 @@
31
31
  <ul class="actions">
32
32
  <li><%= edit_icon(edit_comment_path(id: entity.id)) %></li>
33
33
  <% unless entity.deleted? %>
34
- <li><%= world_icon(CommentsManager.commentable_path(entity, true)) %></li>
34
+ <li><%= world_icon(Biovision::Components::CommentsComponent.commentable_path(entity, true)) %></li>
35
35
  <li class="danger"><%= destroy_icon(entity) %></li>
36
36
  <% end %>
37
37
  </ul>
@@ -14,7 +14,7 @@
14
14
  <ul class="actions">
15
15
  <li><%= back_icon(admin_comments_path) %></li>
16
16
  <% unless @entity.deleted? %>
17
- <li><%= world_icon(CommentsManager.commentable_path(@entity, true)) %></li>
17
+ <li><%= world_icon(Biovision::Components::CommentsComponent.commentable_path(@entity, true)) %></li>
18
18
  <% end %>
19
19
  <% unless @entity.locked? %>
20
20
  <li><%= edit_icon edit_comment_path(id: @entity.id) %></li>
@@ -0,0 +1,18 @@
1
+ <%
2
+ relative_path = Biovision::Components::CommentsComponent.commentable_path(@comment, true)
3
+ protocol = ActionMailer::Base.default_url_options[:protocol] || 'http'
4
+ url = "#{protocol}://" + ActionMailer::Base.default_url_options[:host] + relative_path
5
+ %>
6
+ <p>Здравствуйте, <%= @comment.parent.user.name_for_letter %>.</p>
7
+
8
+ <p>
9
+ На&nbsp;ваш <%= link_to('комментарий', url) %> к&nbsp;записи
10
+ «<%= @comment.commentable_title %>» оставили ответ.
11
+ </p>
12
+
13
+ <figure style="margin-left:0;border-left:2px solid #777777;padding:10px">
14
+ <figcaption style="font-weight:700"><%= @comment.profile_name %>:</figcaption>
15
+ <blockquote>
16
+ <%= simple_format(@comment.body) %>
17
+ </blockquote>
18
+ </figure>
@@ -0,0 +1,18 @@
1
+ <%
2
+ relative_path = Biovision::Components::CommentsComponent.commentable_path(@comment)
3
+ protocol = ActionMailer::Base.default_url_options[:protocol] || 'http'
4
+ url = "#{protocol}://" + ActionMailer::Base.default_url_options[:host] + relative_path
5
+ %>
6
+ <p>Здравствуйте, <%= @comment.commentable.user.name_for_letter %>.</p>
7
+
8
+ <p>
9
+ На&nbsp;вашу запись «<%= link_to(@comment.commentable_title, url) %>»
10
+ оставили комментарий.
11
+ </p>
12
+
13
+ <figure style="margin-left:0;border-left:2px solid #777777;padding:10px">
14
+ <figcaption style="font-weight:700"><%= @comment.profile_name %>:</figcaption>
15
+ <blockquote>
16
+ <%= simple_format(@comment.body) %>
17
+ </blockquote>
18
+ </figure>
@@ -39,6 +39,13 @@
39
39
  <div class="body" itemprop="about">
40
40
  <%= simple_format(comment.body) %>
41
41
  </div>
42
+
43
+ <% if handler.allow?('moderator') && !comment.approved? %>
44
+ <div class="approval-buttons">
45
+ <button class="js-approve-comment button-primary" data-url="<%= approve_admin_comment_path(id: comment.id) %>" type="button"><%= t('admin.comments.entity.in_list.approve') %></button>
46
+ <button class="js-delete-comment button-destroy" data-url="<%= admin_comment_path(id: comment.id) %>" type="button"><%= t(:delete) %></button>
47
+ </div>
48
+ <% end %>
42
49
  </div>
43
50
 
44
51
  <% if show_container %>
@@ -59,6 +59,10 @@
59
59
  <% end %>
60
60
 
61
61
  <div class="required">
62
+ <%
63
+ body_limit = BiovisionComponent['comments'].settings['body_limit'].to_i
64
+ body_limit = 5000 if body_limit < 1
65
+ %>
62
66
  <%= f.label :body %>
63
67
  <%=
64
68
  f.text_area(
@@ -67,7 +71,7 @@
67
71
  required: true,
68
72
  cols: 60,
69
73
  rows: 5,
70
- maxlength: Comment::BODY_LIMIT,
74
+ maxlength: 5000,
71
75
  class: 'auto-expand',
72
76
  data: {
73
77
  min_rows: 5,
@@ -77,7 +81,7 @@
77
81
  )
78
82
  %>
79
83
  <div class="check-result-error hidden" data-field="body"></div>
80
- <div class="guideline"><%= t('.guidelines.body') %></div>
84
+ <div class="guideline"><%= t('.guidelines.body', limit: body_limit) %></div>
81
85
  </div>
82
86
  </div>
83
87
 
@@ -86,8 +86,13 @@ ru:
86
86
  guidelines:
87
87
  author_name: "Максимум 100 символов, обязательное поле."
88
88
  author_email: "Не показывается публично. Максимум 100 символов, обязательное поле."
89
- body: "Максимум 5000 символов."
89
+ body: "Максимум %{limit} символов."
90
90
  disclaimer: "Отправляя комментарий, вы принимаете пользовательское соглашение и даёте своё согласие на обработку ваших персональных данных."
91
+ comment_mailer:
92
+ entry_reply:
93
+ subject: "Новый комментарий к вашей записи"
94
+ comment_reply:
95
+ subject: "Новый ответ на ваш комментарий"
91
96
  biovision:
92
97
  components:
93
98
  comments:
@@ -95,5 +100,11 @@ ru:
95
100
  privileges:
96
101
  moderator: "Модератор"
97
102
  settings:
98
- premoderation: "Премодерация"
99
103
  auto_approve_threshold: "Порог автоматического одобрения"
104
+ body_limit: "Максимальная длина"
105
+ ignore_spam: "Игнорировать спам"
106
+ premoderation: "Премодерация"
107
+ spam_link_threshold: "Порог попаданий шаблона для пометки как спам"
108
+ spam_pattern: "RegEx для ловли спама"
109
+ trap_spam: "Отлавливать спам"
110
+ recaptcha: "Использовать reCaptcha"
@@ -3,14 +3,16 @@
3
3
  # Create row for comments component in components table
4
4
  class CreateCommentsComponent < ActiveRecord::Migration[5.2]
5
5
  def up
6
- slug = Biovision::Components::CommentsComponent::SLUG
6
+ slug = Biovision::Components::CommentsComponent.slug
7
7
  return if BiovisionComponent.exists?(slug: slug)
8
8
 
9
9
  BiovisionComponent.create!(
10
10
  slug: slug,
11
11
  settings: {
12
+ auto_approve_threshold: 3,
12
13
  premoderation: false,
13
- auto_approve_threshold: 3
14
+ spam_link_threshold: 0,
15
+ trap_spam: true
14
16
  }
15
17
  )
16
18
  end
@@ -16,6 +16,7 @@ class CreateComments < ActiveRecord::Migration[5.0]
16
16
  def create_comments_table
17
17
  create_table :comments, comment: 'Comment for commentable item' do |t|
18
18
  t.timestamps
19
+ t.uuid :uuid
19
20
  t.integer :parent_id
20
21
  t.references :user, foreign_key: { on_update: :cascade, on_delete: :cascade }
21
22
  t.references :agent, foreign_key: { on_update: :cascade, on_delete: :nullify }
@@ -25,9 +26,6 @@ class CreateComments < ActiveRecord::Migration[5.0]
25
26
  t.boolean :deleted, default: false, null: false
26
27
  t.boolean :spam, default: false, null: false
27
28
  t.boolean :approved, default: true, null: false
28
- t.integer :upvote_count, default: 0, null: false
29
- t.integer :downvote_count, default: 0, null: false
30
- t.integer :vote_result, default: 0, null: false
31
29
  t.integer :commentable_id, null: false
32
30
  t.string :commentable_type, null: false
33
31
  t.string :author_name
@@ -36,20 +34,32 @@ class CreateComments < ActiveRecord::Migration[5.0]
36
34
  t.jsonb :data, default: {}, null: false
37
35
  end
38
36
 
37
+ add_index :comments, :uuid, unique: true
39
38
  add_index :comments, :data, using: :gin
40
39
  add_index :comments, %i[commentable_id commentable_type]
40
+ add_index :comments, %i[approved agent_id ip]
41
41
  add_foreign_key :comments, :comments, column: :parent_id, on_update: :cascade, on_delete: :cascade
42
+
43
+ execute %(
44
+ create index if not exists
45
+ comments_search_idx on comments
46
+ using gin(to_tsvector('russian', body));
47
+ )
42
48
  end
43
49
 
44
50
  def create_component_record
45
- slug = Biovision::Components::CommentsComponent::SLUG
51
+ slug = Biovision::Components::CommentsComponent.slug
46
52
  return if BiovisionComponent.exists?(slug: slug)
47
53
 
48
54
  BiovisionComponent.create!(
49
55
  slug: slug,
50
56
  settings: {
57
+ auto_approve_threshold: 3,
58
+ body_limit: 5000,
51
59
  premoderation: false,
52
- auto_approve_threshold: 3
60
+ spam_link_threshold: 0,
61
+ trap_spam: true,
62
+ spam_pattern: 'https?://[a-z0-9]+'
53
63
  }
54
64
  )
55
65
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add full-text search for comments
4
+ class AddSearchIndexToComments < ActiveRecord::Migration[5.2]
5
+ def up
6
+ execute %(
7
+ create index if not exists
8
+ comments_search_idx on comments
9
+ using gin(to_tsvector('russian', body));
10
+ )
11
+ end
12
+
13
+ def down
14
+ execute %(drop index if exists comments_search_idx)
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Move vote component fields into data
4
+ class ConvertCommentsVoteData < ActiveRecord::Migration[5.2]
5
+ def up
6
+ return unless column_exists?(:comments, :vote_result)
7
+
8
+ add_column :comments, :uuid, :uuid
9
+
10
+ Comment.order('id asc').each do |comment|
11
+ comment.data['votes'] = {
12
+ up: comment.upvote_count,
13
+ down: comment.downvote_count,
14
+ total: comment.vote_result
15
+ }
16
+ comment.save!
17
+ end
18
+
19
+ remove_column :comments, :upvote_count
20
+ remove_column :comments, :downvote_count
21
+ remove_column :comments, :vote_result
22
+ end
23
+
24
+ def down
25
+ # No rollback needed
26
+ end
27
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Biovision
4
4
  module Comment
5
- VERSION = '0.8.190926.0'
5
+ VERSION = '0.12.200627.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: biovision-comment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.190926.0
4
+ version: 0.12.200627.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Khan-Magomedov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2020-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rails
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '5.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '5.2'
27
- - !ruby/object:Gem::Dependency
28
- name: rails-i18n
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '5.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '5.0'
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: biovision-base
43
15
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +24,6 @@ dependencies:
52
24
  - - ">="
53
25
  - !ruby/object:Gem::Version
54
26
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: kaminari
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
27
  - !ruby/object:Gem::Dependency
70
28
  name: database_cleaner
71
29
  requirement: !ruby/object:Gem::Requirement
@@ -150,14 +108,14 @@ files:
150
108
  - app/models/concerns/commentable_item.rb
151
109
  - app/services/biovision/components/comments_component.rb
152
110
  - app/services/comment_handler.rb
153
- - app/services/comments_manager.rb
154
111
  - app/views/admin/comments/_comment.html.erb
155
112
  - app/views/admin/comments/_nav_item.html.erb
156
113
  - app/views/admin/comments/entity/_in_list.html.erb
157
114
  - app/views/admin/comments/index.html.erb
158
115
  - app/views/admin/comments/show.html.erb
159
116
  - app/views/admin/components/links/_comments.html.erb
160
- - app/views/comment_mailer/entry_reply.text.erb
117
+ - app/views/comment_mailer/comment_reply.html.erb
118
+ - app/views/comment_mailer/entry_reply.html.erb
161
119
  - app/views/comments/_comment.html.erb
162
120
  - app/views/comments/_form.html.erb
163
121
  - app/views/comments/_list.html.erb
@@ -168,11 +126,13 @@ files:
168
126
  - app/views/layouts/biovision/comment/application.html.erb
169
127
  - config/locales/comments-ru.yml
170
128
  - config/routes.rb
129
+ - db/amends/20190203090909_add_fields_to_comments.rb
130
+ - db/amends/20190428212121_add_approved_to_comments.rb
131
+ - db/amends/20190428212122_create_comments_component.rb
132
+ - db/amends/20190628101010_add_data_to_comments.rb
171
133
  - db/migrate/20170914000001_create_comments.rb
172
- - db/migrate/20190203090909_add_fields_to_comments.rb
173
- - db/migrate/20190428212121_add_approved_to_comments.rb
174
- - db/migrate/20190428212122_create_comments_component.rb
175
- - db/migrate/20190628101010_add_data_to_comments.rb
134
+ - db/migrate/20191017202020_add_search_index_to_comments.rb
135
+ - db/migrate/20200208090909_convert_comments_vote_data.rb
176
136
  - lib/biovision/comment.rb
177
137
  - lib/biovision/comment/engine.rb
178
138
  - lib/biovision/comment/version.rb
@@ -196,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
156
  - !ruby/object:Gem::Version
197
157
  version: '0'
198
158
  requirements: []
199
- rubygems_version: 3.0.4
159
+ rubygems_version: 3.1.4
200
160
  signing_key:
201
161
  specification_version: 4
202
162
  summary: Commenting for biovision-based applications
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Tool for handling comments
4
- class CommentsManager
5
- # @param [Comment] comment
6
- # @param [TrueClass|FalseClass] anchor
7
- def self.commentable_path(comment, anchor = false)
8
- method_name = "#{comment.commentable_type}_path".downcase.to_sym
9
- if comment.commentable.respond_to?(:url)
10
- result = comment.commentable.url
11
- anchor ? "#{result}#comment-#{comment.id}" : result
12
- else
13
- "##{method_name}"
14
- end
15
- end
16
- end
@@ -1,7 +0,0 @@
1
- Здравствуйте, <%= @comment.commentable.user.name_for_letter %>.
2
-
3
- На вашу запись «<%= @comment.commentable.title %>»
4
- <%= url_for @comment.commentable %>
5
-
6
- Сам комментарий (<%= @comment.user.nil? ? 'анонимный' : @comment.user.profile_name %>):
7
- <%= @comment.body %>