Since we're going to add an action to remove supports, having a separate controller makes things easier. Note there was a strange piece of code which assumed users were not verified if they couldn't vote investments. Now the code is also strange, since it assumes users are not verified if they can't create votes. We might need to revisit these conditions if our logic changes in the future.
329 lines
15 KiB
Ruby
329 lines
15 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(: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(: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) { create(:budget_investment, budget: accepting_budget, author: user) }
|
|
let(:own_investment_in_reviewing_budget) { create(:budget_investment, budget: reviewing_budget, author: user) }
|
|
let(:own_investment_in_selecting_budget) { create(:budget_investment, budget: selecting_budget, author: user) }
|
|
let(:own_investment_in_balloting_budget) { create(:budget_investment, budget: balloting_budget, author: user) }
|
|
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: true, geozones: [geozone]) }
|
|
let(:expired_poll_from_other_geozone) { create(:poll, :expired, geozone_restricted: true, geozones: [create(:geozone)]) }
|
|
let(:poll) { create(:poll, geozone_restricted: false) }
|
|
let(:poll_from_own_geozone) { create(:poll, geozone_restricted: true, geozones: [geozone]) }
|
|
let(:poll_from_other_geozone) { create(:poll, geozone_restricted: true, geozones: [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) { create(:poll_question, poll: expired_poll_from_own_geozone) }
|
|
let(:expired_poll_question_from_other_geozone) { create(:poll_question, poll: expired_poll_from_other_geozone) }
|
|
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(:vote, 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(:vote_featured, 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
|
|
let(:other_user) { create(:user) }
|
|
|
|
it { should be_able_to(:create, build(:follow, :followed_proposal, user: user)) }
|
|
it { should_not be_able_to(:create, build(:follow, :followed_proposal, user: other_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: other_user)) }
|
|
end
|
|
|
|
describe "other users" do
|
|
let(:other_user) { create(:user) }
|
|
|
|
it { should be_able_to(:show, other_user) }
|
|
it { should_not be_able_to(:edit, other_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
|
|
|
|
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) }
|
|
it { should be_able_to(:vote_featured, 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 "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_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(:vote_featured, 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
|