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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/biovision/comment/comments.scss +11 -0
- data/app/controllers/admin/comments_controller.rb +3 -2
- data/app/controllers/comments_controller.rb +13 -7
- data/app/helpers/comments_helper.rb +2 -1
- data/app/mailers/comment_mailer.rb +20 -2
- data/app/models/comment.rb +23 -6
- data/app/models/concerns/commentable_item.rb +1 -1
- data/app/services/biovision/components/comments_component.rb +80 -9
- data/app/services/comment_handler.rb +1 -2
- data/app/views/admin/comments/entity/_in_list.html.erb +3 -3
- data/app/views/admin/comments/show.html.erb +1 -1
- data/app/views/comment_mailer/comment_reply.html.erb +18 -0
- data/app/views/comment_mailer/entry_reply.html.erb +18 -0
- data/app/views/comments/_comment.html.erb +7 -0
- data/app/views/comments/_form.html.erb +6 -2
- data/config/locales/comments-ru.yml +13 -2
- data/db/{migrate → amends}/20190203090909_add_fields_to_comments.rb +0 -0
- data/db/{migrate → amends}/20190428212121_add_approved_to_comments.rb +0 -0
- data/db/{migrate → amends}/20190428212122_create_comments_component.rb +4 -2
- data/db/{migrate → amends}/20190628101010_add_data_to_comments.rb +0 -0
- data/db/migrate/20170914000001_create_comments.rb +15 -5
- data/db/migrate/20191017202020_add_search_index_to_comments.rb +16 -0
- data/db/migrate/20200208090909_convert_comments_vote_data.rb +27 -0
- data/lib/biovision/comment/version.rb +1 -1
- metadata +11 -51
- data/app/services/comments_manager.rb +0 -16
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcfc0b5b350911016a52aca91b97a22d97fcb9b56db8f9eb9c896461b44bfb4f
|
4
|
+
data.tar.gz: 7fa54e4a1fdab7e2af536625e4997cfa5b8af28d50857193cb09dbd6757014e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
35
|
-
Biovision::Components::CommentsComponent
|
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
|
55
|
-
Biovision::Components::CommentsComponent
|
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
|
-
|
68
|
+
verify_captcha_and_create
|
69
69
|
if @entity.valid?
|
70
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
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]
|
5
|
+
# @param [Integer] comment_id
|
3
6
|
def entry_reply(comment_id)
|
4
7
|
@comment = Comment.find_by(id: comment_id)
|
5
8
|
|
6
|
-
|
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
|
data/app/models/comment.rb
CHANGED
@@ -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.
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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,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]
|
18
|
-
def create_comment(
|
19
|
-
@comment = ::Comment.new(
|
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
|
-
|
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
|
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::
|
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
|
-
(
|
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
|
-
|
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(
|
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(
|
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
|
+
На ваш <%= link_to('комментарий', url) %> к записи
|
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
|
+
На вашу запись «<%= 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:
|
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: "Максимум
|
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"
|
File without changes
|
File without changes
|
@@ -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
|
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
|
-
|
14
|
+
spam_link_threshold: 0,
|
15
|
+
trap_spam: true
|
14
16
|
}
|
15
17
|
)
|
16
18
|
end
|
File without changes
|
@@ -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
|
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
|
-
|
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
|
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.
|
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:
|
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/
|
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/
|
173
|
-
- db/migrate/
|
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.
|
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 %>
|