Files
grecia/spec/models/abilities/common_spec.rb
taitus fd5fa2da79 Refactoring: Move 'vote' action to Votes Controllers
As far as possible I think the code is clearer if we use CRUD actions
rather than custom actions. This will make it easier to add the action
to remove votes in the next commit.

Note that we are adding this line as we need to validate it that a vote
can be created on a debate by the current user:

```authorize! :create, Vote.new(voter: current_user, votable: @debate)```

We have done it this way and not with the following code as you might
expect, as this way two votes are created instead of one.

```load_and_authorize_resource through: :debate, through_association: :votes_for```

This line tries to load the resource @debate and through the association
"votes_for" it tries to create a new vote associated to that debate.
Therefore a vote is created when trying to authorise the resource and
then another one in the create action, when calling @debate.vote_by (which
is called by @debate.register_vote).
2023-10-09 07:21:49 +02:00

368 lines
16 KiB
Ruby

require "rails_helper"
require "cancan/matchers"
describe Abilities::Common do
subject(:ability) { Ability.new(user) }
let(:geozone) { create(:geozone) }
let(:user) { create(:user, geozone: geozone) }
let(:another_user) { create(:user) }
let(:debate) { create(:debate) }
let(:comment) { create(:comment) }
let(:proposal) { create(:proposal) }
let(:own_debate) { create(:debate, author: user) }
let(:own_comment) { create(:comment, author: user) }
let(:own_proposal) { create(:proposal, author: user) }
let(:own_legislation_proposal) { create(:legislation_proposal, author: user) }
let(:legislation_proposal) { create(:legislation_proposal) }
let(:accepting_budget) { create(:budget, :accepting) }
let(:reviewing_budget) { create(:budget, :reviewing) }
let(:selecting_budget) { create(:budget, :selecting) }
let(:balloting_budget) { create(:budget, :balloting) }
let(:investment_in_accepting_budget) { create(:budget_investment, budget: accepting_budget) }
let(:investment_in_reviewing_budget) { create(:budget_investment, budget: reviewing_budget) }
let(:investment_in_selecting_budget) { create(:budget_investment, budget: selecting_budget) }
let(:investment_in_balloting_budget) { create(:budget_investment, budget: balloting_budget) }
let(:own_investment_in_accepting_budget) do
create(:budget_investment, budget: accepting_budget, author: user)
end
let(:own_investment_in_reviewing_budget) do
create(:budget_investment, budget: reviewing_budget, author: user)
end
let(:own_investment_in_selecting_budget) do
create(:budget_investment, budget: selecting_budget, author: user)
end
let(:own_investment_in_balloting_budget) do
create(:budget_investment, budget: balloting_budget, author: user)
end
let(:ballot_in_accepting_budget) { create(:budget_ballot, budget: accepting_budget) }
let(:ballot_in_selecting_budget) { create(:budget_ballot, budget: selecting_budget) }
let(:ballot_in_balloting_budget) { create(:budget_ballot, budget: balloting_budget) }
let(:current_poll) { create(:poll) }
let(:expired_poll) { create(:poll, :expired) }
let(:expired_poll_from_own_geozone) { create(:poll, :expired, geozone_restricted_to: [geozone]) }
let(:expired_poll_from_other_geozone) { create(:poll, :expired, geozone_restricted_to: [create(:geozone)]) }
let(:poll) { create(:poll, geozone_restricted: false) }
let(:poll_from_own_geozone) { create(:poll, geozone_restricted_to: [geozone]) }
let(:poll_from_other_geozone) { create(:poll, geozone_restricted_to: [create(:geozone)]) }
let(:poll_question_from_own_geozone) { create(:poll_question, poll: poll_from_own_geozone) }
let(:poll_question_from_other_geozone) { create(:poll_question, poll: poll_from_other_geozone) }
let(:poll_question_from_all_geozones) { create(:poll_question, poll: poll) }
let(:expired_poll_question_from_own_geozone) do
create(:poll_question, poll: expired_poll_from_own_geozone)
end
let(:expired_poll_question_from_other_geozone) do
create(:poll_question, poll: expired_poll_from_other_geozone)
end
let(:expired_poll_question_from_all_geozones) { create(:poll_question, poll: expired_poll) }
let(:own_proposal_document) { build(:document, documentable: own_proposal) }
let(:proposal_document) { build(:document, documentable: proposal) }
let(:own_budget_investment_document) { build(:document, documentable: own_investment_in_accepting_budget) }
let(:budget_investment_document) { build(:document, documentable: investment_in_accepting_budget) }
let(:own_proposal_image) { build(:image, imageable: own_proposal) }
let(:proposal_image) { build(:image, imageable: proposal) }
let(:own_budget_investment_image) { build(:image, imageable: own_investment_in_accepting_budget) }
let(:budget_investment_image) { build(:image, imageable: investment_in_accepting_budget) }
it { should be_able_to(:index, Debate) }
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(:show, user) }
it { should be_able_to(:edit, user) }
it { should be_able_to(:index, Proposal) }
it { should be_able_to(:show, proposal) }
it { should_not be_able_to(:vote, Proposal) }
it { should_not be_able_to(:comment_as_administrator, debate) }
it { should_not be_able_to(:comment_as_moderator, debate) }
it { should_not be_able_to(:comment_as_administrator, proposal) }
it { should_not be_able_to(:comment_as_moderator, proposal) }
it { should be_able_to(:new, DirectMessage) }
it { should_not be_able_to(:create, DirectMessage) }
it { should_not be_able_to(:show, DirectMessage) }
it { should be_able_to(:destroy, own_proposal_document) }
it { should_not be_able_to(:destroy, proposal_document) }
it { should be_able_to(:destroy, own_budget_investment_document) }
it { should_not be_able_to(:destroy, budget_investment_document) }
it { should be_able_to(:destroy, own_proposal_image) }
it { should_not be_able_to(:destroy, proposal_image) }
it { should be_able_to(:destroy, own_budget_investment_image) }
it { should_not be_able_to(:destroy, budget_investment_image) }
it { should_not be_able_to(:manage, Dashboard::Action) }
it { should_not be_able_to(:manage, LocalCensusRecord) }
describe "Comment" do
it { should be_able_to(:create, Comment) }
it { should be_able_to(:vote, Comment) }
it { should be_able_to(:hide, own_comment) }
it { should_not be_able_to(:hide, comment) }
end
describe "flagging content" do
it { should be_able_to(:flag, debate) }
it { should be_able_to(:unflag, debate) }
it { should be_able_to(:flag, comment) }
it { should be_able_to(:unflag, comment) }
it { should be_able_to(:flag, proposal) }
it { should be_able_to(:unflag, proposal) }
describe "own content" do
it { should_not be_able_to(:flag, own_comment) }
it { should_not be_able_to(:unflag, own_comment) }
it { should_not be_able_to(:flag, own_debate) }
it { should_not be_able_to(:unflag, own_debate) }
it { should_not be_able_to(:flag, own_proposal) }
it { should_not be_able_to(:unflag, own_proposal) }
end
end
describe "follows" do
it { should be_able_to(:create, build(:follow, :followed_proposal, user: user)) }
it { should_not be_able_to(:create, build(:follow, :followed_proposal, user: another_user)) }
it { should be_able_to(:destroy, create(:follow, :followed_proposal, user: user)) }
it { should_not be_able_to(:destroy, create(:follow, :followed_proposal, user: another_user)) }
end
describe "other users" do
it { should be_able_to(:show, another_user) }
it { should_not be_able_to(:edit, another_user) }
end
describe "editing debates" do
let(:own_debate_non_editable) { create(:debate, author: user) }
before { allow(own_debate_non_editable).to receive(:editable?).and_return(false) }
it { should be_able_to(:edit, own_debate) }
it { should_not be_able_to(:edit, debate) } # Not his
it { should_not be_able_to(:edit, own_debate_non_editable) }
end
describe "editing proposals" do
let(:own_proposal_non_editable) { create(:proposal, author: user) }
before { allow(own_proposal_non_editable).to receive(:editable?).and_return(false) }
it { should be_able_to(:edit, own_proposal) }
it { should_not be_able_to(:edit, proposal) } # Not his
it { should_not be_able_to(:edit, own_proposal_non_editable) }
it { should be_able_to(:destroy, own_proposal_image) }
it { should be_able_to(:destroy, own_proposal_document) }
it { should_not be_able_to(:destroy, proposal_image) }
it { should_not be_able_to(:destroy, proposal_document) }
end
it { should_not be_able_to(:edit, own_legislation_proposal) }
it { should_not be_able_to(:update, own_legislation_proposal) }
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)) }
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)) }
end
end
describe "proposals dashboard" do
it { should be_able_to(:dashboard, own_proposal) }
it { should_not be_able_to(:dashboard, proposal) }
end
describe "proposal polls" do
let(:poll) { create(:poll, related: own_proposal) }
it { should be_able_to(:manage_polls, own_proposal) }
it { should_not be_able_to(:manage_polls, proposal) }
it { should_not be_able_to(:stats, poll) }
it { should be_able_to(:results, poll) }
end
describe "proposal mailing" do
it { should be_able_to(:manage_mailing, own_proposal) }
it { should_not be_able_to(:manage_mailing, proposal) }
end
describe "proposal poster" do
it { should be_able_to(:manage_poster, own_proposal) }
it { should_not be_able_to(:manage_poster, proposal) }
end
describe "publishing proposals" do
let(:draft_own_proposal) { create(:proposal, :draft, author: user) }
let(:retired_proposal) { create(:proposal, :draft, :retired, author: user) }
it { should be_able_to(:publish, draft_own_proposal) }
it { should_not be_able_to(:publish, own_proposal) }
it { should_not be_able_to(:publish, proposal) }
it { should_not be_able_to(:publish, retired_proposal) }
end
describe "when level 2 verified" do
let(:own_direct_message) { create(:direct_message, sender: user) }
before { user.update(residence_verified_at: Time.current, confirmed_phone: "1") }
describe "Proposal" do
it { should be_able_to(:vote, Proposal) }
end
describe "Direct Message" do
it { should be_able_to(:new, DirectMessage) }
it { should be_able_to(:create, DirectMessage) }
it { should be_able_to(:show, own_direct_message) }
it { should_not be_able_to(:show, create(:direct_message)) }
end
describe "Poll" do
it { should be_able_to(:answer, current_poll) }
it { should_not be_able_to(:answer, expired_poll) }
it { should be_able_to(:answer, poll_question_from_own_geozone) }
it { should be_able_to(:answer, poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, poll_question_from_other_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_own_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, expired_poll_question_from_other_geozone) }
context "Poll::Answer" do
let(:own_answer) { create(:poll_answer, author: user) }
let(:other_user_answer) { create(:poll_answer) }
let(:expired_poll) { create(:poll, :expired) }
let(:question) { create(:poll_question, :yes_no, poll: expired_poll) }
let(:expired_poll_answer) { create(:poll_answer, author: user, question: question, answer: "Yes") }
it { should be_able_to(:destroy, own_answer) }
it { should_not be_able_to(:destroy, other_user_answer) }
it { should_not be_able_to(:destroy, expired_poll_answer) }
end
context "without geozone" do
before { user.geozone = nil }
it { should_not be_able_to(:answer, poll_question_from_own_geozone) }
it { should be_able_to(:answer, poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, poll_question_from_other_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_own_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, expired_poll_question_from_other_geozone) }
end
end
describe "Budgets" do
it { should be_able_to(:create, investment_in_accepting_budget) }
it { should_not be_able_to(:create, investment_in_selecting_budget) }
it { should_not be_able_to(:create, investment_in_balloting_budget) }
it { should be_able_to(:create, user.votes.build(votable: investment_in_selecting_budget)) }
it { should_not be_able_to(:create, user.votes.build(votable: investment_in_accepting_budget)) }
it { should_not be_able_to(:create, user.votes.build(votable: investment_in_balloting_budget)) }
it { should be_able_to(:destroy, user.votes.create!(votable: investment_in_selecting_budget)) }
it { should_not be_able_to(:destroy, user.votes.create!(votable: investment_in_accepting_budget)) }
it { should_not be_able_to(:destroy, user.votes.create!(votable: investment_in_balloting_budget)) }
it { should_not be_able_to(:destroy, investment_in_accepting_budget) }
it { should_not be_able_to(:destroy, investment_in_reviewing_budget) }
it { should_not be_able_to(:destroy, investment_in_selecting_budget) }
it { should_not be_able_to(:destroy, investment_in_balloting_budget) }
it { should be_able_to(:destroy, own_investment_in_accepting_budget) }
it { should be_able_to(:destroy, own_investment_in_reviewing_budget) }
it { should_not be_able_to(:destroy, own_investment_in_selecting_budget) }
it { should_not be_able_to(:destroy, own_investment_in_balloting_budget) }
it { should be_able_to(:edit, own_investment_in_accepting_budget) }
it { should_not be_able_to(:edit, own_investment_in_reviewing_budget) }
it { should_not be_able_to(:edit, own_investment_in_selecting_budget) }
it { should_not be_able_to(:edit, own_investment_in_balloting_budget) }
it { should be_able_to(:create, ballot_in_balloting_budget) }
it { should_not be_able_to(:create, ballot_in_accepting_budget) }
it { should_not be_able_to(:create, ballot_in_selecting_budget) }
it { should be_able_to(:destroy, own_budget_investment_image) }
it { should be_able_to(:destroy, own_budget_investment_document) }
it { should_not be_able_to(:destroy, budget_investment_image) }
it { should_not be_able_to(:destroy, budget_investment_document) }
end
end
describe "when level 3 verified" do
let(:own_direct_message) { create(:direct_message, sender: user) }
before { user.update(verified_at: Time.current) }
it { should be_able_to(:vote, Proposal) }
it { should be_able_to(:new, DirectMessage) }
it { should be_able_to(:create, DirectMessage) }
it { should be_able_to(:show, own_direct_message) }
it { should_not be_able_to(:show, create(:direct_message)) }
it { should be_able_to(:answer, current_poll) }
it { should_not be_able_to(:answer, expired_poll) }
it { should be_able_to(:answer, poll_question_from_own_geozone) }
it { should be_able_to(:answer, poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, poll_question_from_other_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_own_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, expired_poll_question_from_other_geozone) }
context "without geozone" do
before { user.geozone = nil }
it { should_not be_able_to(:answer, poll_question_from_own_geozone) }
it { should be_able_to(:answer, poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, poll_question_from_other_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_own_geozone) }
it { should_not be_able_to(:answer, expired_poll_question_from_all_geozones) }
it { should_not be_able_to(:answer, expired_poll_question_from_other_geozone) }
end
end
describe "#disable_recommendations" do
it { should be_able_to(:disable_recommendations, Debate) }
it { should be_able_to(:disable_recommendations, Proposal) }
end
it { should_not be_able_to(:read, SDG::Target) }
it { should_not be_able_to(:read, SDG::Manager) }
it { should_not be_able_to(:create, SDG::Manager) }
it { should_not be_able_to(:delete, SDG::Manager) }
end