Merge pull request #2403 from consul/valuation_comments
Valuation comments
This commit is contained in:
@@ -45,12 +45,13 @@ class CommentsController < ApplicationController
|
||||
|
||||
def comment_params
|
||||
params.require(:comment).permit(:commentable_type, :commentable_id, :parent_id,
|
||||
:body, :as_moderator, :as_administrator)
|
||||
:body, :as_moderator, :as_administrator, :valuation)
|
||||
end
|
||||
|
||||
def build_comment
|
||||
@comment = Comment.build(@commentable, current_user, comment_params[:body],
|
||||
comment_params[:parent_id].presence)
|
||||
comment_params[:parent_id].presence,
|
||||
comment_params[:valuation])
|
||||
check_for_special_comments
|
||||
end
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
class Valuation::BudgetInvestmentsController < Valuation::BaseController
|
||||
include FeatureFlags
|
||||
include CommentableActions
|
||||
|
||||
feature_flag :budgets
|
||||
|
||||
before_action :restrict_access_to_assigned_items, only: [:show, :edit, :valuate]
|
||||
before_action :load_budget
|
||||
before_action :load_investment, only: [:show, :edit, :valuate]
|
||||
|
||||
has_orders %w{oldest}, only: [:show, :edit]
|
||||
has_filters %w{valuating valuation_finished}, only: :index
|
||||
|
||||
load_and_authorize_resource :investment, class: "Budget::Investment"
|
||||
@@ -36,8 +39,30 @@ class Valuation::BudgetInvestmentsController < Valuation::BaseController
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
load_comments
|
||||
end
|
||||
|
||||
def edit
|
||||
load_comments
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_comments
|
||||
@commentable = @investment
|
||||
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order, valuations: true)
|
||||
set_comment_flags(@comment_tree.comments)
|
||||
end
|
||||
|
||||
def resource_model
|
||||
Budget::Investment
|
||||
end
|
||||
|
||||
def resource_name
|
||||
resource_model.parameterize('_')
|
||||
end
|
||||
|
||||
def load_budget
|
||||
@budget = Budget.find(params[:budget_id])
|
||||
end
|
||||
|
||||
@@ -55,7 +55,7 @@ module Abilities
|
||||
can [:read, :create, :update, :destroy], Budget::Group
|
||||
can [:read, :create, :update, :destroy], Budget::Heading
|
||||
can [:hide, :update, :toggle_selection], Budget::Investment
|
||||
can :valuate, Budget::Investment
|
||||
can [:valuate, :comment_valuation], Budget::Investment
|
||||
can :create, Budget::ValuatorAssignment
|
||||
|
||||
can [:search, :edit, :update, :create, :index, :destroy], Banner
|
||||
|
||||
@@ -5,8 +5,8 @@ module Abilities
|
||||
def initialize(user)
|
||||
valuator = user.valuator
|
||||
can [:read, :update, :valuate], SpendingProposal
|
||||
can [:read, :update, :valuate], Budget::Investment, id: valuator.investment_ids
|
||||
cannot [:update, :valuate], Budget::Investment, budget: { phase: 'finished' }
|
||||
can [:read, :update, :valuate, :comment_valuation], Budget::Investment, id: valuator.investment_ids
|
||||
cannot [:update, :valuate, :comment_valuation], Budget::Investment, budget: { phase: 'finished' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,7 +34,10 @@ class Budget
|
||||
|
||||
has_many :valuator_assignments, dependent: :destroy
|
||||
has_many :valuators, through: :valuator_assignments
|
||||
has_many :comments, as: :commentable
|
||||
|
||||
has_many :comments, -> {where(valuation: false)}, as: :commentable, class_name: 'Comment'
|
||||
has_many :valuations, -> {where(valuation: true)}, as: :commentable, class_name: 'Comment'
|
||||
|
||||
has_many :milestones
|
||||
|
||||
validates :title, presence: true
|
||||
@@ -86,6 +89,10 @@ class Budget
|
||||
before_validation :set_responsible_name
|
||||
before_validation :set_denormalized_ids
|
||||
|
||||
def comments_count
|
||||
comments.count
|
||||
end
|
||||
|
||||
def url
|
||||
budget_investment_path(budget, self)
|
||||
end
|
||||
|
||||
@@ -20,6 +20,7 @@ class Comment < ActiveRecord::Base
|
||||
validates :commentable_type, inclusion: { in: COMMENTABLE_TYPES }
|
||||
|
||||
validate :validate_body_length
|
||||
validate :comment_valuation, if: -> { valuation }
|
||||
|
||||
belongs_to :commentable, -> { with_hidden }, polymorphic: true, counter_cache: true
|
||||
belongs_to :user, -> { with_hidden }
|
||||
@@ -33,7 +34,8 @@ class Comment < ActiveRecord::Base
|
||||
end
|
||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||
scope :public_for_api, -> do
|
||||
where(%{(comments.commentable_type = 'Debate' and comments.commentable_id in (?)) or
|
||||
not_valuations
|
||||
.where(%{(comments.commentable_type = 'Debate' and comments.commentable_id in (?)) or
|
||||
(comments.commentable_type = 'Proposal' and comments.commentable_id in (?)) or
|
||||
(comments.commentable_type = 'Poll' and comments.commentable_id in (?))},
|
||||
Debate.public_for_api.pluck(:id),
|
||||
@@ -50,13 +52,16 @@ class Comment < ActiveRecord::Base
|
||||
scope :sort_by_oldest, -> { order(created_at: :asc) }
|
||||
scope :sort_descendants_by_oldest, -> { order(created_at: :asc) }
|
||||
|
||||
scope :not_valuations, -> { where(valuation: false) }
|
||||
|
||||
after_create :call_after_commented
|
||||
|
||||
def self.build(commentable, user, body, p_id = nil)
|
||||
new commentable: commentable,
|
||||
def self.build(commentable, user, body, p_id = nil, valuation = false)
|
||||
new(commentable: commentable,
|
||||
user_id: user.id,
|
||||
body: body,
|
||||
parent_id: p_id
|
||||
parent_id: p_id,
|
||||
valuation: valuation)
|
||||
end
|
||||
|
||||
def self.find_commentable(c_type, c_id)
|
||||
@@ -129,4 +134,9 @@ class Comment < ActiveRecord::Base
|
||||
validator.validate(self)
|
||||
end
|
||||
|
||||
def comment_valuation
|
||||
unless author.can?(:comment_valuation, commentable)
|
||||
errors.add(:valuation, :cannot_comment_valuation)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<span id="flag-actions-<%= dom_id(comment) %>" class="js-flag-actions">
|
||||
<%= render 'comments/flag_actions', comment: comment %>
|
||||
</span>
|
||||
<% if local_assigns.fetch(:allow_flagging, true) %>
|
||||
<span id="flag-actions-<%= dom_id(comment) %>" class="js-flag-actions">
|
||||
<%= render 'comments/flag_actions', comment: comment %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<span class='js-moderation-actions'>
|
||||
<% if can? :hide, comment %>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<% comment_flags ||= @comment_flags %>
|
||||
<% valuation = local_assigns.fetch(:valuation, false) %>
|
||||
<% allow_votes = local_assigns.fetch(:allow_votes, true) %>
|
||||
<% allow_flagging = local_assigns.fetch(:allow_flagging, true) %>
|
||||
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author, (comment_flags[comment.id] if comment_flags)] do %>
|
||||
<ul id="<%= dom_id(comment) %>" class="comment no-bullet small-12">
|
||||
<li class="comment-body">
|
||||
@@ -67,9 +70,11 @@
|
||||
</div>
|
||||
|
||||
<div id="<%= dom_id(comment) %>_reply" class="reply">
|
||||
<div id="<%= dom_id(comment) %>_votes" class="comment-votes float-right">
|
||||
<%= render 'comments/votes', comment: comment %>
|
||||
</div>
|
||||
<% if allow_votes %>
|
||||
<div id="<%= dom_id(comment) %>_votes" class="comment-votes float-right">
|
||||
<%= render 'comments/votes', comment: comment %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if comment.children.size > 0 %>
|
||||
<%= link_to "", class: "js-toggle-children relative", data: {'id': "#{dom_id(comment)}"} do %>
|
||||
@@ -86,9 +91,13 @@
|
||||
<%= link_to(comment_link_text(comment), "",
|
||||
class: "js-add-comment-link", data: {'id': dom_id(comment)}) %>
|
||||
|
||||
<%= render 'comments/actions', comment: comment %>
|
||||
<%= render 'comments/actions', { comment: comment,
|
||||
allow_flagging: allow_flagging } %>
|
||||
|
||||
<%= render 'comments/form', {commentable: comment.commentable, parent_id: comment.id, toggeable: true} %>
|
||||
<%= render 'comments/form', {commentable: comment.commentable,
|
||||
parent_id: comment.id,
|
||||
toggeable: true,
|
||||
valuation: valuation } %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -98,7 +107,10 @@
|
||||
<ul id="<%= dom_id(comment) %>_children" class="no-bullet comment-children">
|
||||
<% child_comments_of(comment).each do |child| %>
|
||||
<li>
|
||||
<%= render 'comments/comment', comment: child %>
|
||||
<%= render 'comments/comment', { comment: child,
|
||||
valuation: valuation,
|
||||
allow_votes: allow_votes,
|
||||
allow_flagging: allow_flagging } %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% commentable = comment_tree.commentable %>
|
||||
|
||||
<% valuation = local_assigns.fetch(:valuation, false) %>
|
||||
<% cache [locale_and_user_status, comment_tree.order, commentable_cache_key(commentable), comment_tree.comments, comment_tree.comment_authors, commentable.comments_count, comment_flags] do %>
|
||||
<section class="expanded comments">
|
||||
<div class="row">
|
||||
@@ -27,7 +27,8 @@
|
||||
<% else %>
|
||||
<%= render 'comments/form', { commentable: commentable,
|
||||
parent_id: nil,
|
||||
toggeable: false } %>
|
||||
toggeable: false,
|
||||
valuation: valuation } %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<br>
|
||||
@@ -39,7 +40,11 @@
|
||||
<% end %>
|
||||
|
||||
<% comment_tree.root_comments.each do |comment| %>
|
||||
<%= render 'comments/comment', {comment: comment, comment_flags: comment_flags} %>
|
||||
<%= render 'comments/comment', { comment: comment,
|
||||
comment_flags: comment_flags,
|
||||
valuation: valuation,
|
||||
allow_votes: !valuation,
|
||||
allow_flagging: !valuation } %>
|
||||
<% end %>
|
||||
<%= paginate comment_tree.root_comments %>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<%= render 'comments/form', {commentable: @investment, parent_id: nil, toggeable: false} %>
|
||||
<%= render 'comments/form', { commentable: @investment,
|
||||
parent_id: nil,
|
||||
toggeable: false,
|
||||
valuation: local_assigns.fetch(:valuation, false) } %>
|
||||
<% else %>
|
||||
<br>
|
||||
|
||||
@@ -22,7 +25,8 @@
|
||||
<% end %>
|
||||
|
||||
<% @comment_tree.root_comments.each do |comment| %>
|
||||
<%= render 'comments/comment', comment: comment %>
|
||||
<%= render 'comments/comment', { comment: comment,
|
||||
valuation: local_assigns.fetch(:valuation, false) } %>
|
||||
<% end %>
|
||||
<%= paginate @comment_tree.root_comments %>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<%= f.hidden_field :commentable_type, value: commentable.class.name %>
|
||||
<%= f.hidden_field :commentable_id, value: commentable.id %>
|
||||
<%= f.hidden_field :parent_id, value: parent_id %>
|
||||
<%= f.hidden_field :valuation, value: local_assigns.fetch(:valuation, false) %>
|
||||
|
||||
<%= f.submit comment_button_text(parent_id, commentable), class: "button", id: "publish_comment" %>
|
||||
|
||||
|
||||
@@ -51,3 +51,12 @@
|
||||
<h2><%= t("valuation.budget_investments.show.internal_comments") %></h2>
|
||||
<%= explanation_field @investment.internal_comments %>
|
||||
<% end %>
|
||||
|
||||
<div class="tabs-panel is-active" id="tab-comments">
|
||||
<% unless @comment_tree.nil? %>
|
||||
<%= render partial: '/comments/comment_tree', locals: { comment_tree: @comment_tree,
|
||||
comment_flags: @comment_flags,
|
||||
display_comments_count: false,
|
||||
valuation: true } %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -103,6 +103,15 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="tabs-panel is-active" id="tab-comments">
|
||||
<% unless @comment_tree.nil? %>
|
||||
<%= render partial: '/comments/comment_tree', locals: { comment_tree: @comment_tree,
|
||||
comment_flags: @comment_flags,
|
||||
display_comments_count: false,
|
||||
valuation: true } %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h1><%= @investment.title %></h1>
|
||||
|
||||
<%= safe_html_with_links @investment.description %>
|
||||
|
||||
@@ -296,6 +296,10 @@ en:
|
||||
image:
|
||||
image_width: "Width must be %{required_width}px"
|
||||
image_height: "Height must be %{required_height}px"
|
||||
comment:
|
||||
attributes:
|
||||
valuation:
|
||||
cannot_comment_valuation: 'You cannot comment a valuation'
|
||||
messages:
|
||||
record_invalid: "Validation failed: %{errors}"
|
||||
restrict_dependent_destroy:
|
||||
|
||||
@@ -292,6 +292,10 @@ es:
|
||||
image:
|
||||
image_width: "Debe tener %{required_width}px de ancho"
|
||||
image_height: "Debe tener %{required_height}px de alto"
|
||||
comment:
|
||||
attributes:
|
||||
valuation:
|
||||
cannot_comment_valuation: 'No puedes comentar una evaluación'
|
||||
messages:
|
||||
record_invalid: 'Error de validación: %{errors}'
|
||||
restrict_dependent_destroy:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddValuationFlagToComments < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :comments, :valuation, :boolean, default: false
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
class AddIndexToValuationComments < ActiveRecord::Migration
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :comments, :valuation, algorithm: :concurrently
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180119073228) do
|
||||
ActiveRecord::Schema.define(version: 20180129190950) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -234,7 +234,7 @@ ActiveRecord::Schema.define(version: 20180119073228) do
|
||||
t.string "commentable_type"
|
||||
t.text "body"
|
||||
t.string "subject"
|
||||
t.integer "user_id", null: false
|
||||
t.integer "user_id", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "hidden_at"
|
||||
@@ -247,7 +247,8 @@ ActiveRecord::Schema.define(version: 20180119073228) do
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.datetime "confirmed_hide_at"
|
||||
t.string "ancestry"
|
||||
t.integer "confidence_score", default: 0, null: false
|
||||
t.integer "confidence_score", default: 0, null: false
|
||||
t.boolean "valuation", default: false
|
||||
end
|
||||
|
||||
add_index "comments", ["ancestry"], name: "index_comments_on_ancestry", using: :btree
|
||||
@@ -257,6 +258,7 @@ ActiveRecord::Schema.define(version: 20180119073228) do
|
||||
add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree
|
||||
add_index "comments", ["hidden_at"], name: "index_comments_on_hidden_at", using: :btree
|
||||
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
||||
add_index "comments", ["valuation"], name: "index_comments_on_valuation", using: :btree
|
||||
|
||||
create_table "communities", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
|
||||
@@ -4,16 +4,24 @@ class CommentTree
|
||||
|
||||
attr_accessor :root_comments, :comments, :commentable, :page, :order
|
||||
|
||||
def initialize(commentable, page, order = 'confidence_score')
|
||||
def initialize(commentable, page, order = 'confidence_score', valuations: false)
|
||||
@commentable = commentable
|
||||
@page = page
|
||||
@order = order
|
||||
|
||||
@valuations = valuations
|
||||
@comments = root_comments + root_descendants
|
||||
end
|
||||
|
||||
def root_comments
|
||||
commentable.comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
|
||||
base_comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
|
||||
end
|
||||
|
||||
def base_comments
|
||||
if @valuations && commentable.respond_to?('valuations')
|
||||
commentable.valuations
|
||||
else
|
||||
commentable.comments
|
||||
end
|
||||
end
|
||||
|
||||
def root_descendants
|
||||
|
||||
@@ -465,6 +465,16 @@ FactoryBot.define do
|
||||
trait :with_confidence_score do
|
||||
before(:save) { |d| d.calculate_confidence_score }
|
||||
end
|
||||
|
||||
trait :valuation do
|
||||
valuation true
|
||||
association :commentable, factory: :budget_investment
|
||||
before :create do |valuation|
|
||||
valuator = create(:valuator)
|
||||
valuation.author = valuator.user
|
||||
valuation.commentable.valuators << valuator
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :legacy_legislation do
|
||||
|
||||
@@ -7,16 +7,19 @@ feature 'Commenting Budget::Investments' do
|
||||
|
||||
scenario 'Index' do
|
||||
3.times { create(:comment, commentable: investment) }
|
||||
valuation_comment = create(:comment, :valuation, commentable: investment, subject: 'Not viable')
|
||||
|
||||
visit budget_investment_path(investment.budget, investment)
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
expect(page).not_to have_content('Not viable')
|
||||
|
||||
comment = Comment.last
|
||||
within first('.comment') do
|
||||
expect(page).to have_content comment.user.name
|
||||
expect(page).to have_content I18n.l(comment.created_at, format: :datetime)
|
||||
expect(page).to have_content comment.body
|
||||
within("#comments") do
|
||||
Comment.not_valuations.last(3).each do |comment|
|
||||
expect(page).to have_content comment.user.name
|
||||
expect(page).to have_content I18n.l(comment.created_at, format: :datetime)
|
||||
expect(page).to have_content comment.body
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,6 +27,7 @@ feature 'Commenting Budget::Investments' do
|
||||
parent_comment = create(:comment, commentable: investment)
|
||||
first_child = create(:comment, commentable: investment, parent: parent_comment)
|
||||
second_child = create(:comment, commentable: investment, parent: parent_comment)
|
||||
valuation_comment = create(:comment, :valuation, commentable: investment, subject: 'Not viable')
|
||||
|
||||
visit comment_path(parent_comment)
|
||||
|
||||
@@ -31,6 +35,7 @@ feature 'Commenting Budget::Investments' do
|
||||
expect(page).to have_content parent_comment.body
|
||||
expect(page).to have_content first_child.body
|
||||
expect(page).to have_content second_child.body
|
||||
expect(page).not_to have_content('Not viable')
|
||||
|
||||
expect(page).to have_link "Go back to #{investment.title}", href: budget_investment_path(investment.budget, investment)
|
||||
|
||||
|
||||
300
spec/features/comments/budget_investments_valuation_spec.rb
Normal file
300
spec/features/comments/budget_investments_valuation_spec.rb
Normal file
@@ -0,0 +1,300 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Internal valuation comments on Budget::Investments' do
|
||||
let(:user) { create(:user) }
|
||||
let(:valuator_user) { create(:valuator).user }
|
||||
let(:admin_user) { create(:administrator).user }
|
||||
let(:budget) { create(:budget, :valuating) }
|
||||
let(:investment) { create(:budget_investment, budget: budget) }
|
||||
|
||||
background do
|
||||
Setting['feature.budgets'] = true
|
||||
investment.valuators << valuator_user.valuator
|
||||
login_as(valuator_user)
|
||||
end
|
||||
|
||||
after do
|
||||
Setting['feature.budgets'] = nil
|
||||
end
|
||||
|
||||
context 'Show valuation comments' do
|
||||
context 'Show valuation comments without public comments' do
|
||||
background do
|
||||
public_comment = create(:comment, commentable: investment, body: 'Public comment')
|
||||
create(:comment, commentable: investment, author: valuator_user,
|
||||
body: 'Public valuator comment')
|
||||
create(:comment, commentable: investment, author: admin_user, parent: public_comment)
|
||||
|
||||
valuator_valuation = create(:comment, :valuation, commentable: investment,
|
||||
author: valuator_user,
|
||||
body: 'Valuator Valuation')
|
||||
create(:comment, :valuation, commentable: investment, author: admin_user,
|
||||
body: 'Admin Valuation')
|
||||
admin_response = create(:comment, :valuation, commentable: investment, author: admin_user,
|
||||
body: 'Admin Valuation response',
|
||||
parent: valuator_valuation)
|
||||
create(:comment, :valuation, commentable: investment, author: admin_user,
|
||||
body: 'Valuator Valuation response', parent: admin_response)
|
||||
end
|
||||
|
||||
scenario 'Valuation Show page without public comments' do
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
expect(page).not_to have_content('Comment as admin')
|
||||
expect(page).not_to have_content('Public comment')
|
||||
expect(page).not_to have_content('Public valuator comment')
|
||||
expect(page).to have_content('Leave your comment')
|
||||
expect(page).to have_content('Valuator Valuation')
|
||||
expect(page).to have_content('Admin Valuation')
|
||||
expect(page).to have_content('Admin Valuation response')
|
||||
expect(page).to have_content('Valuator Valuation response')
|
||||
end
|
||||
|
||||
scenario 'Valuation Edit page without public comments' do
|
||||
visit edit_valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
expect(page).not_to have_content('Comment as admin')
|
||||
expect(page).not_to have_content('Public comment')
|
||||
expect(page).not_to have_content('Public valuator comment')
|
||||
expect(page).to have_content('Leave your comment')
|
||||
expect(page).to have_content('Valuator Valuation')
|
||||
expect(page).to have_content('Admin Valuation')
|
||||
expect(page).to have_content('Admin Valuation response')
|
||||
expect(page).to have_content('Valuator Valuation response')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Collapsable comments', :js do
|
||||
parent_comment = create(:comment, :valuation, author: valuator_user, body: "Main comment",
|
||||
commentable: investment)
|
||||
child_comment = create(:comment, :valuation, author: valuator_user, body: "First child",
|
||||
commentable: investment, parent: parent_comment)
|
||||
grandchild_comment = create(:comment, :valuation, author: valuator_user, parent: child_comment,
|
||||
body: "Last child", commentable: investment)
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
|
||||
find("#comment_#{child_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 2)
|
||||
expect(page).not_to have_content grandchild_comment.body
|
||||
|
||||
find("#comment_#{child_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 3)
|
||||
expect(page).to have_content grandchild_comment.body
|
||||
|
||||
find("#comment_#{parent_comment.id}_children_arrow").trigger('click')
|
||||
|
||||
expect(page).to have_css('.comment', count: 1)
|
||||
expect(page).not_to have_content child_comment.body
|
||||
expect(page).not_to have_content grandchild_comment.body
|
||||
end
|
||||
|
||||
scenario 'Comment order' do
|
||||
create(:comment, :valuation, commentable: investment,
|
||||
author: valuator_user,
|
||||
body: 'Valuator Valuation',
|
||||
created_at: Time.current - 1)
|
||||
admin_valuation = create(:comment, :valuation, commentable: investment,
|
||||
author: admin_user,
|
||||
body: 'Admin Valuation',
|
||||
created_at: Time.current - 2)
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
expect(admin_valuation.body).to appear_before('Valuator Valuation')
|
||||
end
|
||||
|
||||
scenario 'Turns links into html links' do
|
||||
create(:comment, :valuation, author: admin_user, commentable: investment,
|
||||
body: 'Check http://rubyonrails.org/')
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
within first('.comment') do
|
||||
expect(page).to have_content('Check http://rubyonrails.org/')
|
||||
expect(page).to have_link('http://rubyonrails.org/', href: 'http://rubyonrails.org/')
|
||||
expect(find_link('http://rubyonrails.org/')[:rel]).to eq('nofollow')
|
||||
expect(find_link('http://rubyonrails.org/')[:target]).to eq('_blank')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Sanitizes comment body for security' do
|
||||
comment_with_js = "<script>alert('hola')</script> <a href=\"javascript:alert('sorpresa!')\">"\
|
||||
"click me<a/> http://www.url.com"
|
||||
create(:comment, :valuation, author: admin_user, commentable: investment,
|
||||
body: comment_with_js)
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
within first('.comment') do
|
||||
expect(page).to have_content("click me http://www.url.com")
|
||||
expect(page).to have_link('http://www.url.com', href: 'http://www.url.com')
|
||||
expect(page).not_to have_link('click me')
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Paginated comments' do
|
||||
per_page = 10
|
||||
(per_page + 2).times do
|
||||
create(:comment, :valuation, commentable: investment, author: valuator_user)
|
||||
end
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
expect(page).to have_css('.comment', count: per_page)
|
||||
within("ul.pagination") do
|
||||
expect(page).to have_content("1")
|
||||
expect(page).to have_content("2")
|
||||
expect(page).not_to have_content("3")
|
||||
click_link "Next", exact: false
|
||||
end
|
||||
|
||||
expect(page).to have_css('.comment', count: 2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'Valuation comment creation' do
|
||||
scenario 'Normal users cannot create valuation comments altering public comments form', :js do
|
||||
logout
|
||||
login_as(user)
|
||||
visit budget_investment_path(investment.budget, investment)
|
||||
|
||||
fill_in "comment-body-budget_investment_#{investment.id}", with: 'HACKERMAN IS HERE'
|
||||
find(:xpath, "//input[@id='comment_valuation']", visible: false).set('true')
|
||||
click_button 'Publish comment'
|
||||
|
||||
visit budget_investment_path(investment.budget, investment)
|
||||
expect(page).not_to have_content('HACKERMAN IS HERE')
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
expect(page).not_to have_content('HACKERMAN IS HERE')
|
||||
end
|
||||
|
||||
scenario 'Create comment', :js do
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
fill_in "comment-body-budget_investment_#{investment.id}", with: 'Have you thought about...?'
|
||||
click_button 'Publish comment'
|
||||
|
||||
within "#comments" do
|
||||
expect(page).to have_content 'Have you thought about...?'
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Errors on create without comment text', :js do
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
click_button 'Publish comment'
|
||||
|
||||
expect(page).to have_content "Can't be blank"
|
||||
end
|
||||
|
||||
scenario 'Reply to existing comment', :js do
|
||||
comment = create(:comment, :valuation, author: admin_user, commentable: investment)
|
||||
|
||||
login_as(valuator_user)
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: 'It will be done next week.'
|
||||
click_button 'Publish reply'
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content 'It will be done next week.'
|
||||
end
|
||||
|
||||
expect(page).not_to have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
|
||||
end
|
||||
|
||||
scenario 'Errors on reply without comment text', :js do
|
||||
comment = create(:comment, :valuation, author: admin_user, commentable: investment)
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
click_button 'Publish reply'
|
||||
expect(page).to have_content "Can't be blank"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
scenario "Multiple nested replies", :js do
|
||||
parent = create(:comment, :valuation, author: valuator_user, commentable: investment)
|
||||
|
||||
7.times do
|
||||
create(:comment, :valuation, author: admin_user, commentable: investment, parent: parent)
|
||||
parent = parent.children.first
|
||||
end
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment")
|
||||
|
||||
expect(page).to have_no_css('.comment-votes')
|
||||
expect(page).to have_no_css('.js-flag-actions')
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Erasing a comment's author" do
|
||||
comment = create(:comment, :valuation, author: valuator_user, commentable: investment,
|
||||
body: "this should be visible")
|
||||
comment.user.erase
|
||||
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content('User deleted')
|
||||
expect(page).to have_content('this should be visible')
|
||||
end
|
||||
end
|
||||
|
||||
feature "Administrators" do
|
||||
scenario "can create valuation comment as an administrator", :js do
|
||||
login_as(admin_user)
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
fill_in "comment-body-budget_investment_#{investment.id}", with: "I am your Admin!"
|
||||
check "comment-as-administrator-budget_investment_#{investment.id}"
|
||||
click_button "Publish comment"
|
||||
|
||||
within "#comments" do
|
||||
expect(page).to have_content "I am your Admin!"
|
||||
expect(page).to have_content "Administrator ##{admin_user.administrator.id}"
|
||||
expect(page).to have_css "div.is-admin"
|
||||
expect(page).to have_css "img.admin-avatar"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "can create valuation reply as an administrator", :js do
|
||||
comment = create(:comment, :valuation, author: valuator_user, commentable: investment)
|
||||
|
||||
login_as(admin_user)
|
||||
visit valuation_budget_budget_investment_path(budget, investment)
|
||||
|
||||
click_link "Reply"
|
||||
|
||||
within "#js-comment-form-comment_#{comment.id}" do
|
||||
fill_in "comment-body-comment_#{comment.id}", with: "Top of the world!"
|
||||
check "comment-as-administrator-comment_#{comment.id}"
|
||||
click_button 'Publish reply'
|
||||
end
|
||||
|
||||
within "#comment_#{comment.id}" do
|
||||
expect(page).to have_content "Top of the world!"
|
||||
expect(page).to have_content "Administrator ##{admin_user.administrator.id}"
|
||||
expect(page).to have_css "div.is-admin"
|
||||
expect(page).to have_css "img.admin-avatar"
|
||||
end
|
||||
|
||||
expect(page).not_to have_selector("#js-comment-form-comment_#{comment.id}", visible: true)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -187,5 +187,11 @@ describe Comment do
|
||||
|
||||
expect(described_class.public_for_api).not_to include(comment)
|
||||
end
|
||||
|
||||
it "does not return internal valuation comments" do
|
||||
valuation_comment = create(:comment, :valuation)
|
||||
|
||||
expect(described_class.public_for_api).not_to include(valuation_comment)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user