Allow undo votes in favor against component

This commit is contained in:
taitus
2023-09-20 15:23:23 +02:00
parent fd5fa2da79
commit 108a05a66d
13 changed files with 137 additions and 11 deletions

View File

@@ -4,7 +4,7 @@
title: t("votes.agree"),
"aria-label": agree_aria_label,
"aria-pressed": pressed?("yes"),
method: "post",
method: user_already_voted_with("yes") ? "delete" : "post",
remote: true do %>
<span class="show-for-sr"><%= t("votes.agree") %></span>
<% end %>
@@ -16,7 +16,7 @@
title: t("votes.disagree"),
"aria-label": disagree_aria_label,
"aria-pressed": pressed?("no"),
method: "post",
method: user_already_voted_with("no") ? "delete" : "post",
remote: true do %>
<span class="show-for-sr"><%= t("votes.disagree") %></span>
<% end %>

View File

@@ -28,10 +28,31 @@ class Shared::InFavorAgainstComponent < ApplicationComponent
end
def vote_in_favor_against_path(value)
if user_already_voted_with(value)
remove_vote_path(value)
else
if votable.class.name == "Debate"
debate_votes_path(votable, value: value)
else
legislation_process_proposal_votes_path(votable.process, votable, value: value)
end
end
end
def user_already_voted_with(value)
current_user&.voted_as_when_voted_for(votable) == parse_vote(value)
end
def remove_vote_path(value)
vote = votable.votes_for.find_by!(voter: current_user)
if votable.class.name == "Debate"
debate_vote_path(votable, vote, value: value)
else
legislation_process_proposal_vote_path(votable.process, votable, vote, value: value)
end
end
def parse_vote(value)
value == "yes" ? true : false
end
end

View File

@@ -2,6 +2,7 @@ module Debates
class VotesController < ApplicationController
before_action :authenticate_user!
load_and_authorize_resource :debate
load_and_authorize_resource through: :debate, through_association: :votes_for, only: :destroy
def create
authorize! :create, Vote.new(voter: current_user, votable: @debate)
@@ -11,5 +12,13 @@ module Debates
format.js { render :show }
end
end
def destroy
@debate.unvote_by(current_user)
respond_to do |format|
format.js { render :show }
end
end
end
end

View File

@@ -4,6 +4,7 @@ module Legislation
before_action :authenticate_user!
load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
load_and_authorize_resource through: :proposal, through_association: :votes_for, only: :destroy
def create
authorize! :create, Vote.new(voter: current_user, votable: @proposal)
@@ -13,6 +14,14 @@ module Legislation
format.js { render :show }
end
end
def destroy
@proposal.unvote_by(current_user)
respond_to do |format|
format.js { render :show }
end
end
end
end
end

View File

@@ -81,14 +81,14 @@ module Abilities
can [:create, :destroy], DirectUpload
unless user.organization?
can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
can :vote, Comment
end
if user.level_two_or_three_verified?
can :vote, Proposal, &:published?
can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Legislation::Proposal"
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Legislation::Proposal"
can :create, Legislation::Answer

View File

@@ -11,5 +11,5 @@ resources :debates do
put "recommendations/disable", only: :index, controller: "debates", action: :disable_recommendations
end
resources :votes, controller: "debates/votes", only: :create
resources :votes, controller: "debates/votes", only: [:create, :destroy]
end

View File

@@ -23,7 +23,7 @@ namespace :legislation do
get :suggest
end
resources :votes, controller: "proposals/votes", only: :create
resources :votes, controller: "proposals/votes", only: [:create, :destroy]
end
resources :draft_versions, only: [:show] do

View File

@@ -22,6 +22,24 @@ describe Shared::InFavorAgainstComponent do
end
end
it "can undo vote when the user has already voted" do
create(:vote, votable: debate, voter: user)
sign_in user
render_inline component
page.find(".in-favor") do |in_favor_block|
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
page.find(".against") do |against_block|
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
it "does not include result percentages" do
create(:vote, votable: debate)
sign_in(user)

View File

@@ -40,4 +40,17 @@ describe Debates::VotesController do
end
end
end
describe "DELETE destroy" do
let(:user) { create(:user) }
let(:debate) { create(:debate) }
let!(:vote) { create(:vote, votable: debate, voter: user) }
before { sign_in user }
it "allows undoing a vote if user is allowed" do
expect do
delete :destroy, xhr: true, params: { debate_id: debate.id, id: vote }
end.to change { debate.reload.votes_for.size }.by(-1)
end
end
end

View File

@@ -37,4 +37,20 @@ describe Legislation::Proposals::VotesController do
end.not_to change { proposal.reload.votes_for.size }
end
end
describe "DELETE destroy" do
let(:user) { create(:user, :level_two) }
let!(:vote) { create(:vote, votable: proposal, voter: user) }
let(:vote_params) do
{ process_id: legislation_process.id, legislation_proposal_id: proposal.id, id: vote }
end
it "allows undoing a vote" do
sign_in user
expect do
delete :destroy, xhr: true, params: vote_params
end.to change { proposal.reload.votes_for.size }.by(-1)
end
end
end

View File

@@ -77,6 +77,8 @@ describe Abilities::Common do
it { should be_able_to(:show, debate) }
it { should be_able_to(:create, user.votes.build(votable: debate)) }
it { should_not be_able_to(:create, another_user.votes.build(votable: debate)) }
it { should be_able_to(:destroy, user.votes.build(votable: debate)) }
it { should_not be_able_to(:destroy, another_user.votes.build(votable: debate)) }
it { should be_able_to(:show, user) }
it { should be_able_to(:edit, user) }
@@ -184,12 +186,15 @@ describe Abilities::Common do
describe "vote legislation proposal" do
context "when user is not level_two_or_three_verified" do
it { should_not be_able_to(:create, user.votes.build(votable: legislation_proposal)) }
it { should_not be_able_to(:destroy, user.votes.build(votable: legislation_proposal)) }
end
context "when user is level_two_or_three_verified" do
before { user.update(level_two_verified_at: Date.current) }
it { should be_able_to(:create, user.votes.build(votable: legislation_proposal)) }
it { should_not be_able_to(:create, another_user.votes.build(votable: legislation_proposal)) }
it { should be_able_to(:destroy, user.votes.build(votable: legislation_proposal)) }
it { should_not be_able_to(:destroy, another_user.votes.build(votable: legislation_proposal)) }
end
end

View File

@@ -15,6 +15,7 @@ describe "Abilities::Organization" do
it { should be_able_to(:index, Debate) }
it { should be_able_to(:show, debate) }
it { should_not be_able_to(:create, user.votes.build(votable: debate)) }
it { should_not be_able_to(:destroy, user.votes.build(votable: debate)) }
it { should be_able_to(:index, Proposal) }
it { should be_able_to(:show, proposal) }

View File

@@ -100,20 +100,27 @@ describe "Votes" do
expect(page).to have_content "1 vote"
end
scenario "Trying to vote multiple times" do
scenario "Allow undoing votes" do
visit debate_path(create(:debate))
click_button "I agree"
expect(page).to have_content "1 vote"
expect(page).not_to have_content "No votes"
click_button "I agree"
expect(page).to have_content "No votes"
expect(page).not_to have_content "2 votes"
within(".in-favor") do
expect(page).to have_content "100%"
expect(page).to have_content "0%"
expect(page).to have_css "button[aria-pressed='false']"
end
within(".against") do
expect(page).to have_content "0%"
expect(page).to have_css "button[aria-pressed='false']"
end
end
@@ -337,4 +344,31 @@ describe "Votes" do
expect(page).not_to have_button "Support", disabled: :all
end
end
describe "Legislation Proposals" do
let(:proposal) { create(:legislation_proposal) }
scenario "Allow undoing votes" do
login_as verified
visit legislation_process_proposal_path(proposal.process, proposal)
click_button "I agree"
expect(page).to have_content "1 vote"
expect(page).not_to have_content "No votes"
click_button "I agree"
expect(page).to have_content "No votes"
expect(page).not_to have_content "2 votes"
within(".in-favor") do
expect(page).to have_content "0%"
end
within(".against") do
expect(page).to have_content "0%"
end
end
end
end