Allow undo votes in comments votes component

This commit is contained in:
taitus
2023-09-20 16:10:36 +02:00
parent f87a332c3e
commit 718fcba6d8
16 changed files with 101 additions and 36 deletions

View File

@@ -4,8 +4,8 @@
<span class="in-favor"> <span class="in-favor">
<%= button_to vote_in_favor_against_path("yes"), <%= button_to vote_in_favor_against_path("yes"),
method: "post", method: user_already_voted_with("yes") ? "delete" : "post",
remote: can?(:create, comment.votes_for.new(voter: current_user)), remote: remote_submit("yes"),
"aria-pressed": pressed?("yes"), "aria-pressed": pressed?("yes"),
title: t("votes.agree") do %> title: t("votes.agree") do %>
<span class="show-for-sr"><%= t("votes.agree") %></span> <span class="show-for-sr"><%= t("votes.agree") %></span>
@@ -15,8 +15,8 @@
<span class="against"> <span class="against">
<%= button_to vote_in_favor_against_path("no"), <%= button_to vote_in_favor_against_path("no"),
method: "post", method: user_already_voted_with("no") ? "delete" : "post",
remote: can?(:create, comment.votes_for.new(voter: current_user)), remote: remote_submit("no"),
"aria-pressed": pressed?("no"), "aria-pressed": pressed?("no"),
title: t("votes.disagree") do %> title: t("votes.disagree") do %>
<span class="show-for-sr"><%= t("votes.disagree") %></span> <span class="show-for-sr"><%= t("votes.disagree") %></span>

View File

@@ -18,6 +18,28 @@ class Comments::VotesComponent < ApplicationComponent
end end
def vote_in_favor_against_path(value) def vote_in_favor_against_path(value)
comment_votes_path(comment, value: value) if user_already_voted_with(value)
vote = comment.votes_for.find_by!(voter: current_user)
comment_vote_path(comment, vote, value: value)
else
comment_votes_path(comment, value: value)
end
end
def user_already_voted_with(value)
current_user&.voted_as_when_voted_for(comment) == parse_vote(value)
end
def parse_vote(value)
value == "yes" ? true : false
end
def remote_submit(value)
if user_already_voted_with(value)
can?(:destroy, comment.votes_for.new(voter: current_user))
else
can?(:create, comment.votes_for.new(voter: current_user))
end
end end
end end

View File

@@ -1,7 +1,8 @@
module Comments module Comments
class VotesController < ApplicationController class VotesController < ApplicationController
load_and_authorize_resource :comment
before_action :authenticate_user! before_action :authenticate_user!
load_and_authorize_resource :comment
load_and_authorize_resource through: :comment, through_association: :votes_for, only: :destroy
before_action :verify_comments_open! before_action :verify_comments_open!
def create def create
@@ -13,6 +14,14 @@ module Comments
end end
end end
def destroy
@comment.unvote_by(current_user)
respond_to do |format|
format.js { render :show }
end
end
private private
def verify_comments_open! def verify_comments_open!

View File

@@ -82,7 +82,7 @@ module Abilities
unless user.organization? unless user.organization?
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate" can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Comment" can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Comment"
end end
if user.level_two_or_three_verified? if user.level_two_or_three_verified?

View File

@@ -5,5 +5,5 @@ resources :comments, only: [:create, :show] do
put :hide put :hide
end end
resources :votes, controller: "comments/votes", only: :create resources :votes, controller: "comments/votes", only: [:create, :destroy]
end end

View File

@@ -5,8 +5,8 @@ describe Comments::VotesComponent do
let(:comment) { create(:comment, user: user) } let(:comment) { create(:comment, user: user) }
let(:component) { Comments::VotesComponent.new(comment) } let(:component) { Comments::VotesComponent.new(comment) }
describe "aria-pressed attribute" do describe "aria-pressed and method attributes" do
it "is true when the in-favor button is pressed" do it "have expected values when the in-favor button is pressed" do
comment.vote_by(voter: user, vote: "yes") comment.vote_by(voter: user, vote: "yes")
sign_in(user) sign_in(user)
@@ -14,14 +14,18 @@ describe Comments::VotesComponent do
page.find(".in-favor") do |in_favor_block| page.find(".in-favor") do |in_favor_block|
expect(in_favor_block).to have_css "button[aria-pressed='true']" expect(in_favor_block).to have_css "button[aria-pressed='true']"
expect(in_favor_block).to have_css "form[action*='votes'][method='post']"
expect(in_favor_block).to have_css "input[name='_method'][value='delete']", visible: :hidden
end end
page.find(".against") do |against_block| page.find(".against") do |against_block|
expect(against_block).to have_css "button[aria-pressed='false']" expect(against_block).to have_css "button[aria-pressed='false']"
expect(against_block).to have_css "form[action*='votes'][method='post']"
expect(against_block).not_to have_css "input[name='_method']", visible: :all
end end
end end
it "is true when the against button is pressed" do it "have expected values when the against button is pressed" do
comment.vote_by(voter: user, vote: "no") comment.vote_by(voter: user, vote: "no")
sign_in(user) sign_in(user)
@@ -29,24 +33,32 @@ describe Comments::VotesComponent do
page.find(".in-favor") do |in_favor_block| page.find(".in-favor") do |in_favor_block|
expect(in_favor_block).to have_css "button[aria-pressed='false']" expect(in_favor_block).to have_css "button[aria-pressed='false']"
expect(in_favor_block).to have_css "form[action*='votes'][method='post']"
expect(in_favor_block).not_to have_css "input[name='_method']", visible: :all
end end
page.find(".against") do |against_block| page.find(".against") do |against_block|
expect(against_block).to have_css "button[aria-pressed='true']" expect(against_block).to have_css "button[aria-pressed='true']"
expect(against_block).to have_css "form[action*='votes'][method='post']"
expect(against_block).to have_css "input[name='_method'][value='delete']", visible: :hidden
end end
end end
it "is false when neither the 'in-favor' button nor the 'against' button are pressed" do it "have expected values when neither the 'in-favor' button nor the 'against' button are pressed" do
sign_in(user) sign_in(user)
render_inline component render_inline component
page.find(".in-favor") do |in_favor_block| page.find(".in-favor") do |in_favor_block|
expect(in_favor_block).to have_css "button[aria-pressed='false']" expect(in_favor_block).to have_css "button[aria-pressed='false']"
expect(in_favor_block).to have_css "form[action*='votes'][method='post']"
expect(in_favor_block).not_to have_css "input[name='_method']", visible: :all
end end
page.find(".against") do |against_block| page.find(".against") do |against_block|
expect(against_block).to have_css "button[aria-pressed='false']" expect(against_block).to have_css "button[aria-pressed='false']"
expect(against_block).to have_css "form[action*='votes'][method='post']"
expect(against_block).not_to have_css "input[name='_method']", visible: :all
end end
end end
end end

View File

@@ -12,4 +12,23 @@ describe Comments::VotesController do
end.to change { comment.reload.votes_for.size }.by(1) end.to change { comment.reload.votes_for.size }.by(1)
end end
end end
describe "DELETE destroy" do
let(:user) { create(:user) }
let!(:vote) { create(:vote, votable: comment, voter: user) }
it "redirects unidentified users to the sign in page" do
delete :destroy, params: { comment_id: comment.id, id: vote }
expect(response).to redirect_to new_user_session_path
end
it "allows undoing a vote" do
sign_in user
expect do
delete :destroy, xhr: true, params: { comment_id: comment.id, id: vote }
end.to change { comment.reload.votes_for.size }.by(-1)
end
end
end end

View File

@@ -115,6 +115,8 @@ describe Abilities::Common do
it { should be_able_to(:create, Comment) } it { should be_able_to(:create, Comment) }
it { should be_able_to(:create, user.votes.build(votable: comment)) } it { should be_able_to(:create, user.votes.build(votable: comment)) }
it { should_not be_able_to(:create, another_user.votes.build(votable: comment)) } it { should_not be_able_to(:create, another_user.votes.build(votable: comment)) }
it { should be_able_to(:destroy, user.votes.build(votable: comment)) }
it { should_not be_able_to(:destroy, another_user.votes.build(votable: comment)) }
it { should be_able_to(:hide, own_comment) } it { should be_able_to(:hide, own_comment) }
it { should_not be_able_to(:hide, comment) } it { should_not be_able_to(:hide, comment) }

View File

@@ -24,6 +24,7 @@ describe "Abilities::Organization" do
it { should be_able_to(:create, Comment) } it { should be_able_to(:create, Comment) }
it { should_not be_able_to(:create, user.votes.build(votable: comment)) } it { should_not be_able_to(:create, user.votes.build(votable: comment)) }
it { should_not be_able_to(:destroy, user.votes.build(votable: comment)) }
it { should_not be_able_to(:read, SDG::Target) } it { should_not be_able_to(:read, SDG::Target) }

View File

@@ -578,7 +578,7 @@ describe "Commenting Budget::Investments" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit budget_investment_path(budget, investment) visit budget_investment_path(budget, investment)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -591,14 +591,14 @@ describe "Commenting Budget::Investments" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -614,7 +614,7 @@ describe "Commenting debates" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit debate_path(debate) visit debate_path(debate)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -626,14 +626,14 @@ describe "Commenting debates" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).not_to have_content "2" expect(page).not_to have_content "2"
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -550,7 +550,7 @@ describe "Commenting legislation questions" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit polymorphic_path(annotation) visit polymorphic_path(annotation)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -562,14 +562,14 @@ describe "Commenting legislation questions" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).not_to have_content "2" expect(page).not_to have_content "2"
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -534,7 +534,7 @@ describe "Commenting legislation questions" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit legislation_process_question_path(question.process, question) visit legislation_process_question_path(question.process, question)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -546,14 +546,14 @@ describe "Commenting legislation questions" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).not_to have_content "2" expect(page).not_to have_content "2"
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -495,7 +495,7 @@ describe "Commenting polls" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit poll_path(poll) visit poll_path(poll)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -508,14 +508,14 @@ describe "Commenting polls" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -500,7 +500,7 @@ describe "Commenting proposals" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit proposal_path(proposal) visit proposal_path(proposal)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -513,14 +513,14 @@ describe "Commenting proposals" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end

View File

@@ -547,7 +547,7 @@ describe "Commenting topics from proposals" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit community_topic_path(proposal.community, topic) visit community_topic_path(proposal.community, topic)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -560,14 +560,14 @@ describe "Commenting topics from proposals" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end
@@ -1060,7 +1060,7 @@ describe "Commenting topics from budget investments" do
end end
end end
scenario "Trying to vote multiple times" do scenario "Allow undoing votes" do
visit community_topic_path(investment.community, topic) visit community_topic_path(investment.community, topic)
within("#comment_#{comment.id}_votes") do within("#comment_#{comment.id}_votes") do
@@ -1073,14 +1073,14 @@ describe "Commenting topics from budget investments" do
click_button "I agree" click_button "I agree"
within(".in-favor") do within(".in-favor") do
expect(page).to have_content "1" expect(page).to have_content "0"
end end
within(".against") do within(".against") do
expect(page).to have_content "0" expect(page).to have_content "0"
end end
expect(page).to have_content "1 vote" expect(page).to have_content "No votes"
end end
end end
end end