biovision-comment 0.1.170914 → 0.7.190905.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 +5 -5
- data/README.md +68 -14
- data/app/assets/javascripts/biovision/comment/biovision-comments.js +118 -0
- data/app/assets/stylesheets/biovision/comment/comments.scss +111 -38
- data/app/controllers/admin/comments_controller.rb +18 -5
- data/app/controllers/comments_controller.rb +45 -32
- data/app/helpers/comments_helper.rb +20 -0
- data/app/models/comment.rb +88 -19
- data/app/models/concerns/commentable_item.rb +15 -0
- data/app/services/biovision/components/comments_component.rb +39 -0
- data/app/services/comment_handler.rb +49 -0
- data/app/services/comments_manager.rb +24 -0
- data/app/views/admin/comments/entity/_in_list.html.erb +8 -5
- data/app/views/admin/comments/index.html.erb +2 -1
- data/app/views/admin/comments/show.html.erb +25 -10
- data/app/views/admin/components/links/_comments.html.erb +3 -0
- data/app/views/comment_mailer/entry_reply.text.erb +2 -6
- data/app/views/comments/_comment.html.erb +66 -16
- data/app/views/comments/_form.html.erb +92 -19
- data/app/views/comments/_list.html.erb +17 -19
- data/app/views/comments/_reply_container.html.erb +15 -0
- data/app/views/comments/_section.html.erb +34 -0
- data/app/views/comments/edit.html.erb +6 -5
- data/app/views/comments/new.html.erb +2 -2
- data/config/locales/comments-ru.yml +32 -2
- data/config/routes.rb +18 -10
- data/db/migrate/20170914000001_create_comments.rb +48 -23
- data/db/migrate/20190203090909_add_fields_to_comments.rb +14 -0
- data/db/migrate/20190428212121_add_approved_to_comments.rb +14 -0
- data/db/migrate/20190428212122_create_comments_component.rb +21 -0
- data/db/migrate/20190628101010_add_data_to_comments.rb +15 -0
- data/lib/biovision/comment/engine.rb +7 -2
- data/lib/biovision/comment/version.rb +3 -1
- metadata +19 -8
- data/app/views/comments/show.html.erb +0 -27
@@ -1,25 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Comments
|
1
4
|
class CommentsController < ApplicationController
|
2
|
-
before_action :
|
3
|
-
before_action :restrict_access, except: [
|
4
|
-
before_action :set_entity, only: [
|
5
|
+
before_action :set_handler
|
6
|
+
before_action :restrict_access, except: %i[check create]
|
7
|
+
before_action :set_entity, only: %i[edit update destroy]
|
8
|
+
|
9
|
+
layout 'admin', except: :create
|
5
10
|
|
6
|
-
|
11
|
+
# post /comments/check
|
12
|
+
def check
|
13
|
+
@entity = Comment.instance_for_check(params[:entity_id], entity_parameters)
|
14
|
+
|
15
|
+
render 'shared/forms/check'
|
16
|
+
end
|
7
17
|
|
8
18
|
# post /comments
|
9
19
|
def create
|
10
|
-
|
11
|
-
|
12
|
-
notify_participants
|
13
|
-
redirect_to(@entity.commentable || admin_comment_path(@entity.id), notice: t('comments.create.success'))
|
20
|
+
if params.key?(:agree)
|
21
|
+
emulate_creation
|
14
22
|
else
|
15
|
-
|
23
|
+
create_comment
|
16
24
|
end
|
17
25
|
end
|
18
26
|
|
19
|
-
# get /comments/:id
|
20
|
-
def show
|
21
|
-
end
|
22
|
-
|
23
27
|
# get /comments/:id/edit
|
24
28
|
def edit
|
25
29
|
end
|
@@ -27,9 +31,9 @@ class CommentsController < ApplicationController
|
|
27
31
|
# patch /comments/:id
|
28
32
|
def update
|
29
33
|
if @entity.update entity_parameters
|
30
|
-
|
34
|
+
form_processed_ok(admin_comment_path(id: @entity.id))
|
31
35
|
else
|
32
|
-
|
36
|
+
form_processed_with_error(:edit)
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
@@ -43,36 +47,45 @@ class CommentsController < ApplicationController
|
|
43
47
|
|
44
48
|
private
|
45
49
|
|
50
|
+
def component_slug
|
51
|
+
Biovision::Components::CommentsComponent::SLUG
|
52
|
+
end
|
53
|
+
|
46
54
|
def restrict_access
|
47
|
-
|
55
|
+
error = 'Managing comments is not allowed'
|
56
|
+
handle_http_401(error) unless component_handler.allow?('moderator')
|
57
|
+
end
|
58
|
+
|
59
|
+
def emulate_creation
|
60
|
+
form_processed_ok(root_path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_comment
|
64
|
+
@entity = component_handler.create_comment(creation_parameters)
|
65
|
+
if @entity.valid?
|
66
|
+
notify_participants
|
67
|
+
next_page = param_from_request(:return_url)
|
68
|
+
form_processed_ok(next_page.match?(%r{\A/[^/]}) ? next_page : root_path)
|
69
|
+
else
|
70
|
+
form_processed_with_error(:new)
|
71
|
+
end
|
48
72
|
end
|
49
73
|
|
50
74
|
def set_entity
|
51
75
|
@entity = Comment.find_by(id: params[:id])
|
52
|
-
if @entity.nil?
|
53
|
-
handle_http_404('Cannot find comment')
|
54
|
-
end
|
76
|
+
handle_http_404('Cannot find comment') if @entity.nil?
|
55
77
|
end
|
56
78
|
|
57
79
|
def entity_parameters
|
58
|
-
|
59
|
-
params.require(:comment).permit(permitted)
|
80
|
+
params.require(:comment).permit(Comment.entity_parameters)
|
60
81
|
end
|
61
82
|
|
62
83
|
def creation_parameters
|
63
|
-
|
84
|
+
permitted = Comment.creation_parameters
|
85
|
+
params.require(:comment).permit(permitted).merge(owner_for_entity(true))
|
64
86
|
end
|
65
87
|
|
66
88
|
def notify_participants
|
67
|
-
|
68
|
-
unless commentable.owned_by?(current_user)
|
69
|
-
category = Notification.category_from_object(commentable)
|
70
|
-
Notification.notify(commentable.user, category, commentable.id)
|
71
|
-
# begin
|
72
|
-
# Comments.entry_reply(@entity).deliver_now if @entity.notify_entry_owner?
|
73
|
-
# rescue Net::SMTPAuthenticationError => error
|
74
|
-
# logger.warn error.message
|
75
|
-
# end
|
76
|
-
end
|
89
|
+
# to be implemented...
|
77
90
|
end
|
78
91
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Helper methods for handling comments
|
4
|
+
module CommentsHelper
|
5
|
+
# @param [Comment] entity
|
6
|
+
# @param [String] text
|
7
|
+
# @param [Hash] options
|
8
|
+
def admin_comment_link(entity, text = entity.text_for_link, options = {})
|
9
|
+
link_to(text, admin_comment_path(id: entity.id), options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [Comment] entity
|
13
|
+
# @param [String] text
|
14
|
+
# @param [Hash] options
|
15
|
+
def comment_link(entity, text = entity.commentable_name, options = {})
|
16
|
+
anchor = options.key?(:anchor)
|
17
|
+
options.delete(:anchor)
|
18
|
+
link_to(text, CommentsManager.commentable_path(entity, anchor), options)
|
19
|
+
end
|
20
|
+
end
|
data/app/models/comment.rb
CHANGED
@@ -1,53 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Comment
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# agent_id [Agent], optional
|
7
|
+
# approved [Boolean]
|
8
|
+
# author_email [String], optional
|
9
|
+
# author_name [String], optional
|
10
|
+
# body [Text]
|
11
|
+
# commentable_id [Integer]
|
12
|
+
# commentable_type [String]
|
13
|
+
# created_at [DateTime]
|
14
|
+
# deleted [Boolean]
|
15
|
+
# downvote_count [Integer]
|
16
|
+
# ip [Inet], optional
|
17
|
+
# locked [Boolean]
|
18
|
+
# parent_id [Comment], optional
|
19
|
+
# spam [Boolean]
|
20
|
+
# updated_at [DateTime]
|
21
|
+
# upvote_count [Integer]
|
22
|
+
# visible [Boolean]
|
23
|
+
# vote_result [Integer]
|
1
24
|
class Comment < ApplicationRecord
|
25
|
+
include Checkable
|
2
26
|
include HasOwner
|
3
27
|
include Toggleable
|
4
|
-
include VotableItem
|
28
|
+
include VotableItem if Gem.loaded_specs.key?('biovision-vote')
|
5
29
|
|
6
|
-
|
30
|
+
AUTHOR_LIMIT = 100
|
31
|
+
BODY_LIMIT = 1_048_576
|
7
32
|
|
8
33
|
toggleable :visible
|
9
34
|
|
10
|
-
belongs_to :user, optional: true
|
35
|
+
belongs_to :user, optional: true
|
11
36
|
belongs_to :agent, optional: true
|
12
37
|
belongs_to :commentable, polymorphic: true, counter_cache: true, touch: false
|
38
|
+
belongs_to :parent, class_name: Comment.to_s, optional: true
|
39
|
+
has_many :child_comments, class_name: Comment.to_s, foreign_key: :parent_id, dependent: :destroy
|
13
40
|
|
14
41
|
validates_presence_of :body
|
42
|
+
validates_length_of :body, maximum: BODY_LIMIT
|
43
|
+
validates_length_of :author_name, maximum: AUTHOR_LIMIT
|
44
|
+
validates_length_of :author_email, maximum: AUTHOR_LIMIT
|
15
45
|
validate :commentable_is_commentable
|
16
46
|
|
47
|
+
after_create { commentable.comment_impact(self) if commentable.respond_to?(:comment_impact) }
|
48
|
+
|
17
49
|
scope :recent, -> { order 'id desc' }
|
18
|
-
scope :
|
50
|
+
scope :chronological, -> { order 'id asc' }
|
51
|
+
scope :visible, -> { where(deleted: false, visible: true, spam: false) } #, approved: true) }
|
52
|
+
scope :list_for_administration, -> { recent }
|
53
|
+
scope :list_for_visitors, -> { visible.chronological }
|
54
|
+
scope :list_for_visitors_recent, -> { visible.recent }
|
55
|
+
scope :list_for_owner, ->(v) { owned_by(v).where(deleted: false).recent }
|
19
56
|
|
20
57
|
# @param [Integer] page
|
21
|
-
def self.page_for_administration(page)
|
22
|
-
|
58
|
+
def self.page_for_administration(page = 1)
|
59
|
+
list_for_administration.page(page)
|
23
60
|
end
|
24
61
|
|
25
62
|
# @param [Integer] page
|
26
|
-
def self.page_for_visitor(page)
|
27
|
-
|
63
|
+
def self.page_for_visitor(page = 1)
|
64
|
+
list_for_visitors.page(page)
|
28
65
|
end
|
29
66
|
|
30
67
|
# @param [User] user
|
31
68
|
# @param [Integer] page
|
32
|
-
def self.page_for_owner(user, page)
|
33
|
-
|
69
|
+
def self.page_for_owner(user, page = 1)
|
70
|
+
list_for_owner(user).page(page)
|
34
71
|
end
|
35
72
|
|
36
73
|
def self.entity_parameters
|
37
|
-
%i
|
74
|
+
%i[author_name author_email body]
|
38
75
|
end
|
39
76
|
|
40
77
|
def self.creation_parameters
|
41
|
-
entity_parameters + %i
|
78
|
+
entity_parameters + %i[commentable_id commentable_type parent_id]
|
42
79
|
end
|
43
80
|
|
44
81
|
def self.administrative_parameters
|
45
|
-
entity_parameters + %i
|
82
|
+
entity_parameters + %i[deleted visible spam]
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.tree(collection)
|
86
|
+
result = {}
|
87
|
+
|
88
|
+
collection.each do |entity|
|
89
|
+
result[entity.id] = {
|
90
|
+
parent_id: entity.parent_id,
|
91
|
+
comment: entity,
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
result
|
46
96
|
end
|
47
97
|
|
48
98
|
# @param [User] user
|
49
99
|
def visible_to?(user)
|
50
|
-
if
|
100
|
+
if commentable.respond_to? :visible_to?
|
51
101
|
if deleted?
|
52
102
|
UserPrivilege.user_has_privilege?(user, :administrator) && commentable.visible_to?(user)
|
53
103
|
else
|
@@ -67,13 +117,32 @@ class Comment < ApplicationRecord
|
|
67
117
|
end
|
68
118
|
end
|
69
119
|
|
120
|
+
def text_for_link
|
121
|
+
"#{self.class.model_name.human} #{id}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def commentable_name
|
125
|
+
"#{commentable.class.model_name.human} #{commentable_id}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def commentable_title
|
129
|
+
if commentable.respond_to?(:title)
|
130
|
+
commentable.title
|
131
|
+
else
|
132
|
+
commentable_name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def profile_name
|
137
|
+
user.nil? ? author_name : user.profile_name
|
138
|
+
end
|
139
|
+
|
70
140
|
private
|
71
141
|
|
72
142
|
def commentable_is_commentable
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
143
|
+
return unless commentable.respond_to?(:commentable_by?)
|
144
|
+
return if commentable.commentable_by?(user)
|
145
|
+
|
146
|
+
errors.add(:commentable, I18n.t('activerecord.errors.models.comment.attributes.commentable.not_commentable'))
|
78
147
|
end
|
79
148
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Adds "commentable" behavior to entity
|
4
|
+
module CommentableItem
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :comments, as: :commentable, dependent: :destroy
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [User] user
|
12
|
+
def commentable_by?(user)
|
13
|
+
!user.nil?
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Biovision
|
4
|
+
module Components
|
5
|
+
# Handler for Biovision Comments
|
6
|
+
class CommentsComponent < BaseComponent
|
7
|
+
SLUG = 'comments'
|
8
|
+
|
9
|
+
def self.privilege_names
|
10
|
+
%w[moderator]
|
11
|
+
end
|
12
|
+
|
13
|
+
def use_parameters?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Hash] parameters
|
18
|
+
def create_comment(parameters)
|
19
|
+
@comment = ::Comment.new(parameters)
|
20
|
+
@comment.save
|
21
|
+
@comment
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
# @param [Hash] data
|
27
|
+
# @return [Hash]
|
28
|
+
def normalize_settings(data)
|
29
|
+
result = {}
|
30
|
+
flags = %w[premoderation]
|
31
|
+
flags.each { |f| result[f] = data[f].to_i == 1 }
|
32
|
+
numbers = %w[auto_approve_threshold]
|
33
|
+
numbers.each { |f| result[f] = data[f].to_i }
|
34
|
+
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Handler for working with comments
|
4
|
+
class CommentHandler
|
5
|
+
attr_accessor :user
|
6
|
+
|
7
|
+
# @param [User] user
|
8
|
+
def initialize(user = nil)
|
9
|
+
slug = Biovision::Components::CommentsComponent::SLUG
|
10
|
+
@user = user
|
11
|
+
@handler = Biovision::Components::BaseComponent.handler(slug)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get list of comments for entity
|
15
|
+
#
|
16
|
+
# Depending on privileges, receives list for visitors (only visible
|
17
|
+
# and approved) or all comments (including deleted).
|
18
|
+
#
|
19
|
+
# @param [ApplicationRecord] entity
|
20
|
+
def list(entity)
|
21
|
+
if @handler.class.allow?(@user)
|
22
|
+
entity.comments.list_for_administration
|
23
|
+
else
|
24
|
+
entity.comments.list_for_visitors
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Auto-approve comment from current user?
|
29
|
+
#
|
30
|
+
# If premoderation flag is not set, every comment is automatically approved.
|
31
|
+
# If premoderation flag is set, difference between approved and non-approved
|
32
|
+
# comments must be more than threshold; anonymous comments are always
|
33
|
+
# non-approved.
|
34
|
+
def approve?
|
35
|
+
return true unless @component.settings['premoderate']
|
36
|
+
return false if @user.nil?
|
37
|
+
return true if @component.class.allow?(@user)
|
38
|
+
|
39
|
+
gate = @component.settings['auto_approve_threshold'].to_i
|
40
|
+
positive = Comment.where(user: @user, approved: true).count
|
41
|
+
negative = Comment.where(user: @user, approved: false).count
|
42
|
+
positive - negative >= gate
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [ApplicationRecord] entity
|
46
|
+
def allow_reply?(entity)
|
47
|
+
entity.respond_to?(:commentable_by?) && entity.commentable_by?(@user)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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 respond_to?(method_name)
|
10
|
+
result = send(method_name, comment.commentable)
|
11
|
+
anchor ? "#{result}#comment-#{comment.id}" : result
|
12
|
+
else
|
13
|
+
"##{method_name}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Post] entity
|
18
|
+
def self.post_path(entity)
|
19
|
+
return '#post' unless Gem.loaded_specs.key?('biovision-post')
|
20
|
+
|
21
|
+
handler = PostManager.new(entity)
|
22
|
+
handler.post_path
|
23
|
+
end
|
24
|
+
end
|
@@ -6,23 +6,26 @@
|
|
6
6
|
<%= admin_comment_link(entity) %>
|
7
7
|
|
8
8
|
<% if entity.deleted? %>
|
9
|
-
|
9
|
+
(<%= t('activerecord.attributes.comment.deleted') %>)
|
10
10
|
<% end %>
|
11
11
|
</div>
|
12
12
|
|
13
13
|
<div class="info">
|
14
|
+
<%= entity.commentable_name %>
|
15
|
+
(<%= entity.commentable_title %>)<br/>
|
14
16
|
<%= admin_user_link(entity.user) %>,
|
15
17
|
<%= time_tag entity.created_at %>
|
16
18
|
</div>
|
17
19
|
|
18
|
-
<div class="info">
|
19
|
-
<%=
|
20
|
+
<div class="secondary info">
|
21
|
+
<%= simple_format(entity.body) %>
|
20
22
|
</div>
|
21
23
|
|
22
24
|
<ul class="actions">
|
23
|
-
<li><%= edit_icon(edit_comment_path(entity.id)) %></li>
|
25
|
+
<li><%= edit_icon(edit_comment_path(id: entity.id)) %></li>
|
24
26
|
<% unless entity.deleted? %>
|
25
|
-
|
27
|
+
<li><%= world_icon(CommentsManager.commentable_path(entity, true)) %></li>
|
28
|
+
<li class="danger"><%= destroy_icon(entity) %></li>
|
26
29
|
<% end %>
|
27
30
|
</ul>
|
28
31
|
</div>
|