biovision-comment 0.8.190926.0 → 0.12.200627.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 %>