Allow undo votes in favor against component
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
title: t("votes.agree"),
|
title: t("votes.agree"),
|
||||||
"aria-label": agree_aria_label,
|
"aria-label": agree_aria_label,
|
||||||
"aria-pressed": pressed?("yes"),
|
"aria-pressed": pressed?("yes"),
|
||||||
method: "post",
|
method: user_already_voted_with("yes") ? "delete" : "post",
|
||||||
remote: true do %>
|
remote: true do %>
|
||||||
<span class="show-for-sr"><%= t("votes.agree") %></span>
|
<span class="show-for-sr"><%= t("votes.agree") %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
title: t("votes.disagree"),
|
title: t("votes.disagree"),
|
||||||
"aria-label": disagree_aria_label,
|
"aria-label": disagree_aria_label,
|
||||||
"aria-pressed": pressed?("no"),
|
"aria-pressed": pressed?("no"),
|
||||||
method: "post",
|
method: user_already_voted_with("no") ? "delete" : "post",
|
||||||
remote: true do %>
|
remote: true do %>
|
||||||
<span class="show-for-sr"><%= t("votes.disagree") %></span>
|
<span class="show-for-sr"><%= t("votes.disagree") %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -28,10 +28,31 @@ class Shared::InFavorAgainstComponent < ApplicationComponent
|
|||||||
end
|
end
|
||||||
|
|
||||||
def vote_in_favor_against_path(value)
|
def vote_in_favor_against_path(value)
|
||||||
|
if user_already_voted_with(value)
|
||||||
|
remove_vote_path(value)
|
||||||
|
else
|
||||||
if votable.class.name == "Debate"
|
if votable.class.name == "Debate"
|
||||||
debate_votes_path(votable, value: value)
|
debate_votes_path(votable, value: value)
|
||||||
else
|
else
|
||||||
legislation_process_proposal_votes_path(votable.process, votable, value: value)
|
legislation_process_proposal_votes_path(votable.process, votable, value: value)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ module Debates
|
|||||||
class VotesController < ApplicationController
|
class VotesController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
load_and_authorize_resource :debate
|
load_and_authorize_resource :debate
|
||||||
|
load_and_authorize_resource through: :debate, through_association: :votes_for, only: :destroy
|
||||||
|
|
||||||
def create
|
def create
|
||||||
authorize! :create, Vote.new(voter: current_user, votable: @debate)
|
authorize! :create, Vote.new(voter: current_user, votable: @debate)
|
||||||
@@ -11,5 +12,13 @@ module Debates
|
|||||||
format.js { render :show }
|
format.js { render :show }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@debate.unvote_by(current_user)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.js { render :show }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ module Legislation
|
|||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
load_and_authorize_resource :process, class: "Legislation::Process"
|
load_and_authorize_resource :process, class: "Legislation::Process"
|
||||||
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :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
|
def create
|
||||||
authorize! :create, Vote.new(voter: current_user, votable: @proposal)
|
authorize! :create, Vote.new(voter: current_user, votable: @proposal)
|
||||||
@@ -13,6 +14,14 @@ module Legislation
|
|||||||
format.js { render :show }
|
format.js { render :show }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@proposal.unvote_by(current_user)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.js { render :show }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -81,14 +81,14 @@ module Abilities
|
|||||||
can [:create, :destroy], DirectUpload
|
can [:create, :destroy], DirectUpload
|
||||||
|
|
||||||
unless user.organization?
|
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
|
can :vote, Comment
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.level_two_or_three_verified?
|
if user.level_two_or_three_verified?
|
||||||
can :vote, Proposal, &:published?
|
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
|
can :create, Legislation::Answer
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ resources :debates do
|
|||||||
put "recommendations/disable", only: :index, controller: "debates", action: :disable_recommendations
|
put "recommendations/disable", only: :index, controller: "debates", action: :disable_recommendations
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :votes, controller: "debates/votes", only: :create
|
resources :votes, controller: "debates/votes", only: [:create, :destroy]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace :legislation do
|
|||||||
get :suggest
|
get :suggest
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :votes, controller: "proposals/votes", only: :create
|
resources :votes, controller: "proposals/votes", only: [:create, :destroy]
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :draft_versions, only: [:show] do
|
resources :draft_versions, only: [:show] do
|
||||||
|
|||||||
@@ -22,6 +22,24 @@ describe Shared::InFavorAgainstComponent do
|
|||||||
end
|
end
|
||||||
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
|
it "does not include result percentages" do
|
||||||
create(:vote, votable: debate)
|
create(:vote, votable: debate)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
|||||||
@@ -40,4 +40,17 @@ describe Debates::VotesController do
|
|||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -37,4 +37,20 @@ describe Legislation::Proposals::VotesController do
|
|||||||
end.not_to change { proposal.reload.votes_for.size }
|
end.not_to change { proposal.reload.votes_for.size }
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ describe Abilities::Common do
|
|||||||
it { should be_able_to(:show, debate) }
|
it { should be_able_to(:show, debate) }
|
||||||
it { should be_able_to(:create, user.votes.build(votable: 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_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(:show, user) }
|
||||||
it { should be_able_to(:edit, user) }
|
it { should be_able_to(:edit, user) }
|
||||||
@@ -184,12 +186,15 @@ describe Abilities::Common do
|
|||||||
describe "vote legislation proposal" do
|
describe "vote legislation proposal" do
|
||||||
context "when user is not level_two_or_three_verified" 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(:create, user.votes.build(votable: legislation_proposal)) }
|
||||||
|
it { should_not be_able_to(:destroy, user.votes.build(votable: legislation_proposal)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when user is level_two_or_three_verified" do
|
context "when user is level_two_or_three_verified" do
|
||||||
before { user.update(level_two_verified_at: Date.current) }
|
before { user.update(level_two_verified_at: Date.current) }
|
||||||
it { should be_able_to(:create, user.votes.build(votable: legislation_proposal)) }
|
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_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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ describe "Abilities::Organization" do
|
|||||||
it { should be_able_to(:index, Debate) }
|
it { should be_able_to(:index, Debate) }
|
||||||
it { should be_able_to(:show, 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(: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(:index, Proposal) }
|
||||||
it { should be_able_to(:show, proposal) }
|
it { should be_able_to(:show, proposal) }
|
||||||
|
|||||||
@@ -100,20 +100,27 @@ describe "Votes" do
|
|||||||
expect(page).to have_content "1 vote"
|
expect(page).to have_content "1 vote"
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Trying to vote multiple times" do
|
scenario "Allow undoing votes" do
|
||||||
visit debate_path(create(:debate))
|
visit debate_path(create(:debate))
|
||||||
|
|
||||||
click_button "I agree"
|
click_button "I agree"
|
||||||
|
|
||||||
expect(page).to have_content "1 vote"
|
expect(page).to have_content "1 vote"
|
||||||
|
expect(page).not_to have_content "No votes"
|
||||||
|
|
||||||
click_button "I agree"
|
click_button "I agree"
|
||||||
|
|
||||||
|
expect(page).to have_content "No votes"
|
||||||
expect(page).not_to have_content "2 votes"
|
expect(page).not_to have_content "2 votes"
|
||||||
|
|
||||||
within(".in-favor") do
|
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
|
end
|
||||||
|
|
||||||
within(".against") do
|
within(".against") do
|
||||||
expect(page).to have_content "0%"
|
expect(page).to have_content "0%"
|
||||||
|
expect(page).to have_css "button[aria-pressed='false']"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -337,4 +344,31 @@ describe "Votes" do
|
|||||||
expect(page).not_to have_button "Support", disabled: :all
|
expect(page).not_to have_button "Support", disabled: :all
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user