Implement track request acceptance

Allow track submitter to request specific dates
Redirect to Tracks#edit if a track doesn't have a room or start/end date
before accepting it

Don't allow the submitter or the track organizers to edit the request
after it has been accepted or confirmed

Restrict track selection in proposals and move track selection from
Proposals form to events helper

Mark cfp_active of the tracks table as not null and fill in true if nil
This commit is contained in:
AEtherC0r3 2017-07-14 15:57:34 +03:00 committed by Stella Rouzi
parent 2f9eb04219
commit d9faffc96a
27 changed files with 909 additions and 62 deletions

View file

@ -26,6 +26,7 @@ describe 'User' do
let(:program_with_cfp) { create(:program, :with_cfp) }
let(:program_without_cfp) { create(:program) }
let(:program_with_call_for_tracks) { create(:cfp, cfp_type: 'tracks').program }
let(:conference_with_open_registration) { create(:conference) }
let!(:open_registration_period) { create(:registration_period, conference: conference_with_open_registration, start_date: Date.current - 6.days) }
let(:conference_with_closed_registration) { create(:conference) }
@ -82,6 +83,10 @@ describe 'User' do
let(:user_event_with_cfp) { create(:event, users: [user], program: program_with_cfp) }
let(:user_commercial) { create(:commercial, commercialable: user_event_with_cfp) }
let(:user_self_organized_track) { create(:track, :self_organized, submitter: user) }
let(:accepted_user_self_organized_track) { create(:track, :self_organized, submitter: user, state: 'accepted') }
let(:confirmed_user_self_organized_track) { create(:track, :self_organized, submitter: user, state: 'confirmed') }
let(:other_self_organized_track) { create(:track, :self_organized) }
it{ should be_able_to(:manage, user) }
@ -114,6 +119,31 @@ describe 'User' do
it{ should be_able_to(:create, user_event_with_cfp.commercials.new) }
it{ should be_able_to(:manage, user_commercial) }
it{ should_not be_able_to(:manage, commercial_event_unconfirmed) }
it{ should be_able_to(:new, Track.new(program: program_with_call_for_tracks)) }
it{ should be_able_to(:create, Track.new(program: program_with_call_for_tracks)) }
it{ should_not be_able_to(:new, Track.new(program: program_without_cfp)) }
it{ should_not be_able_to(:create, Track.new(program: program_without_cfp)) }
it{ should be_able_to(:index, user_self_organized_track) }
it{ should be_able_to(:show, user_self_organized_track) }
it{ should be_able_to(:restart, user_self_organized_track) }
it{ should be_able_to(:confirm, user_self_organized_track) }
it{ should be_able_to(:withdraw, user_self_organized_track) }
it{ should_not be_able_to(:index, other_self_organized_track) }
it{ should_not be_able_to(:show, other_self_organized_track) }
it{ should_not be_able_to(:restart, other_self_organized_track) }
it{ should_not be_able_to(:confirm, other_self_organized_track) }
it{ should_not be_able_to(:withdraw, other_self_organized_track) }
it{ should be_able_to(:edit, user_self_organized_track) }
it{ should be_able_to(:update, user_self_organized_track) }
it{ should_not be_able_to(:edit, accepted_user_self_organized_track) }
it{ should_not be_able_to(:update, accepted_user_self_organized_track) }
it{ should_not be_able_to(:edit, confirmed_user_self_organized_track) }
it{ should_not be_able_to(:update, confirmed_user_self_organized_track) }
it{ should_not be_able_to(:edit, other_self_organized_track) }
it{ should_not be_able_to(:update, other_self_organized_track) }
end
end
end

View file

@ -44,7 +44,7 @@ describe 'User with admin role' do
let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) }
let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) }
let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program) }
let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed') }
context 'user #is_admin?' do
let(:venue) { my_conference.venue }
@ -505,6 +505,8 @@ describe 'User with admin role' do
it{ should be_able_to(:show, my_conference.program) }
it{ should be_able_to(:update, new_track) }
it{ should be_able_to(:manage, my_self_organized_track) }
it{ should_not be_able_to(:edit, my_self_organized_track) }
it{ should_not be_able_to(:update, my_self_organized_track) }
it_behaves_like 'user with any role'
it_behaves_like 'user with non-organizer role', 'track_organizer'

View file

@ -606,8 +606,8 @@ describe Conference do
describe 'tracks_distribution' do
before do
subject.email_settings = create(:email_settings)
@track_one = create(:track, name: 'Track One', color: '#000000')
@track_two = create(:track, name: 'Track Two', color: '#ffffff')
@track_one = create(:track, name: 'Track One', color: '#000000', program: subject.program)
@track_two = create(:track, name: 'Track Two', color: '#ffffff', program: subject.program)
end
describe '#tracks_distribution' do

View file

@ -96,6 +96,40 @@ describe Event do
end
end
end
describe '#acceptable_track' do
context 'is valid' do
it 'when the track belong to the same program, is confirmed and is included in the cfp' do
track = create(:track, state: 'confirmed', cfp_active: true, program: conference.program)
event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq true
end
end
context 'is invalid' do
it 'when the track doesn\'t have the same program' do
track = create(:track, state: 'confirmed', cfp_active: true)
event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid']
end
it 'when the track is unconfirmed' do
track = create(:track, cfp_active: true, program: conference.program)
allow(track).to receive(:confirmed?).and_return(false)
event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid']
end
it 'when the track isn\'t included in the cfp' do
track = create(:track, state: 'confirmed', cfp_active: false, program: conference.program)
event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid']
end
end
end
end
describe '#comments_count' do

View file

@ -8,6 +8,7 @@ describe Track do
describe 'association' do
it { is_expected.to belong_to(:program) }
it { is_expected.to belong_to(:submitter).class_name('User') }
it { is_expected.to belong_to(:room) }
it { is_expected.to have_many(:events) }
end
@ -23,23 +24,99 @@ describe Track do
it { is_expected.to allow_value('My_track_name').for(:short_name) }
it { is_expected.to_not allow_value('My track name').for(:short_name) }
it { is_expected.to validate_uniqueness_of(:short_name).scoped_to(:program_id) }
it { is_expected.to validate_presence_of(:state) }
it { is_expected.to validate_inclusion_of(:state).in_array(%w[new to_accept accepted confirmed to_reject rejected canceled withdrawn]) }
it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) }
context 'when self-organized' do
context 'when self_organized_and_accepted_or_confirmed? returns true' do
before :each do
allow(subject).to receive(:self_organized?).and_return(true)
allow(subject).to receive(:self_organized_and_accepted_or_confirmed?).and_return(true)
end
it { is_expected.to validate_presence_of(:state) }
it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) }
it { is_expected.to validate_presence_of(:start_date) }
it { is_expected.to validate_presence_of(:end_date) }
it { is_expected.to validate_presence_of(:room) }
end
context 'when regular' do
context 'when self_organized_and_accepted_or_confirmed? returns false' do
before :each do
allow(subject).to receive(:self_organized?).and_return(false)
allow(subject).to receive(:self_organized_and_accepted_or_confirmed?).and_return(false)
end
it { is_expected.to_not validate_presence_of(:state) }
it { is_expected.to_not validate_inclusion_of(:cfp_active) }
it { is_expected.to_not validate_presence_of(:start_date) }
it { is_expected.to_not validate_presence_of(:end_date) }
it { is_expected.to_not validate_presence_of(:room) }
end
describe '#valid_dates' do
before :each do
@conference = create(:conference, start_date: 1.day.ago, end_date: 2.days.from_now)
end
context 'is valid' do
it 'when the track\'s start date is before it\'s end date and between the conference start/end dates' do
track = build(:track, start_date: Date.today, end_date: Date.tomorrow, program: @conference.program)
expect(track.valid?).to eq true
end
end
context 'is invalid' do
it 'when the track\'s start date is before the conference\'s start date' do
track = build(:track, start_date: 2.days.ago, end_date: Date.tomorrow, program: @conference.program)
expect(track.valid?).to eq false
expect(track.errors[:start_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"]
end
it 'when the track\'s end date is before the conference\'s start date' do
track = build(:track, start_date: 3.days.ago, end_date: 2.days.ago, program: @conference.program)
expect(track.valid?).to eq false
expect(track.errors[:end_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"]
end
it 'when the track\'s start date is after the conference\'s end date' do
track = build(:track, start_date: 3.days.from_now, end_date: 4.days.from_now, program: @conference.program)
expect(track.valid?).to eq false
expect(track.errors[:start_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"]
end
it 'when the track\'s end date is after the conference\'s end date' do
track = build(:track, start_date: Date.today, end_date: 3.days.from_now, program: @conference.program)
expect(track.valid?).to eq false
expect(track.errors[:end_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"]
end
it 'when the track\'s start date is after it\'s end date' do
track = build(:track, start_date: 1.day.from_now, end_date: 1.day.ago)
expect(track.valid?).to eq false
expect(track.errors[:start_date]).to eq ['can\'t be after the end date']
end
end
end
describe '#valid_room' do
before :each do
@conference = create(:conference)
@conference.venue = create(:venue, name: 'The venue')
end
context 'is valid' do
it 'when the track\'s room belongs to the venue of the conference' do
room = create(:room, venue: @conference.venue)
track = build(:track, :self_organized, state: 'accepted', program: @conference.program, room: room)
expect(track.valid?).to eq true
end
end
context 'is invalid' do
it 'when the track\'s room doesn\'t belong to the venue of the track\'s conference' do
other_conference = create(:conference)
other_conference.venue = create(:venue)
room = create(:room, venue: other_conference.venue)
track = build(:track, :self_organized, state: 'accepted', program: @conference.program, room: room)
expect(track.valid?).to eq false
expect(track.errors[:room]).to eq ['must be a room of The venue']
end
end
end
end
@ -54,4 +131,226 @@ describe Track do
expect(track.self_organized?).to eq false
end
end
describe '#transition_possible?' do
shared_examples 'transition_possible?' do |state, transition, expected|
it "returns #{expected} for #{transition} event, when the track's state is #{state}}" do
my_self_organized_track = create(:track, :self_organized, state: state)
expect(my_self_organized_track.transition_possible?(transition.to_sym)).to eq expected
end
end
states = [:new, :to_accept, :accepted, :confirmed, :to_reject, :rejected, :canceled, :withdrawn]
transitions = [:restart, :to_accept, :accept, :confirm, :to_reject, :reject, :cancel, :withdraw]
states_transitions = { new: { restart: false, to_accept: true, accept: true, confirm: false, to_reject: true, reject: true, cancel: false, withdraw: true },
to_accept: { restart: false, to_accept: false, accept: true, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true },
accepted: { restart: false, to_accept: false, accept: false, confirm: true, to_reject: false, reject: false, cancel: true, withdraw: true },
confirmed: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true },
to_reject: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: true, cancel: true, withdraw: true },
rejected: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false },
canceled: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false },
withdrawn: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false } }
states.each do |state|
transitions.each do |transition|
it_behaves_like 'transition_possible?', state, transition, states_transitions[state.to_sym][transition.to_sym]
end
end
end
describe '#assign_role_to_submitter' do
before :each do
Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create
@submitter = self_organized_track.submitter
end
it 'gives the role of the track organizer to the submitter of the track' do
expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq false
self_organized_track.assign_role_to_submitter
expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq true
end
it 'is executed when the track is confirmed' do
self_organized_track.state = 'accepted'
self_organized_track.save!
expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq false
self_organized_track.confirm
expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq true
end
end
describe '#revoke_role_and_cleanup' do
before :each do
Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create
@a_track_organizer = create(:user)
self_organized_track.state = 'confirmed'
self_organized_track.cfp_active = true
self_organized_track.save!
@a_track_organizer.add_role 'track_organizer', self_organized_track
@an_event_of_the_track = create(:event, program: self_organized_track.program, track: self_organized_track)
end
it 'revokes the role of the track organizer' do
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq true
self_organized_track.revoke_role_and_cleanup
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
end
it 'removes the track from the events that have it set' do
expect(@an_event_of_the_track.track).to eq self_organized_track
self_organized_track.revoke_role_and_cleanup
@an_event_of_the_track.reload
expect(@an_event_of_the_track.track).to eq nil
end
it 'is executed when the track is canceled' do
self_organized_track.state = 'confirmed'
self_organized_track.save!
self_organized_track.cancel
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
@an_event_of_the_track.reload
expect(@an_event_of_the_track.track).to eq nil
end
it 'is executed when the track is withdrawn' do
self_organized_track.withdraw
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
@an_event_of_the_track.reload
expect(@an_event_of_the_track.track).to eq nil
end
end
describe '#accepted?' do
context 'returns true' do
it 'when the state is "accepted"' do
self_organized_track.state = 'accepted'
self_organized_track.save!
expect(self_organized_track.accepted?).to eq true
end
end
context 'returns false' do
%w[new to_accept confirmed to_reject rejected canceled withdrawn].each do |state|
it "when the state is \"#{state}\"" do
self_organized_track.state = state
self_organized_track.save!
expect(self_organized_track.accepted?).to eq false
end
end
end
end
describe '#confirmed?' do
context 'returns true' do
it 'when the state is "confirmed"' do
self_organized_track.state = 'confirmed'
self_organized_track.save!
expect(self_organized_track.confirmed?).to eq true
end
end
context 'returns false' do
%w[new to_accept accepted to_reject rejected canceled withdrawn].each do |state|
it "when the state is \"#{state}\"" do
self_organized_track.state = state
self_organized_track.save!
expect(self_organized_track.confirmed?).to eq false
end
end
end
end
# accepted? and confirmed? are mutually exclusive (they can't be both true)
describe '#self_organized_and_accepted_or_confirmed?' do
context 'returns true' do
context 'when self_organized? returns true' do
before :each do
allow(track).to receive(:self_organized?).and_return(true)
end
context 'accepted? returns true and confirmed? returns false' do
before :each do
allow(track).to receive(:accepted?).and_return(true)
allow(track).to receive(:confirmed?).and_return(false)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq true }
end
context 'accepted? returns false and confirmed? returns true' do
before :each do
allow(track).to receive(:accepted?).and_return(false)
allow(track).to receive(:confirmed?).and_return(true)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq true }
end
end
end
context 'returns false' do
context 'when self_organized? returns true' do
before :each do
allow(track).to receive(:self_organized?).and_return(true)
end
context 'accepted? returns false and confirmed? returns false' do
before :each do
allow(track).to receive(:accepted?).and_return(false)
allow(track).to receive(:confirmed?).and_return(false)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false }
end
end
context 'when self_organized? returns false' do
before :each do
allow(track).to receive(:self_organized?).and_return(false)
end
context 'accepted? returns false and confirmed? returns false' do
before :each do
allow(track).to receive(:accepted?).and_return(false)
allow(track).to receive(:confirmed?).and_return(false)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false }
end
context 'accepted? returns true and confirmed? returns false' do
before :each do
allow(track).to receive(:accepted?).and_return(true)
allow(track).to receive(:confirmed?).and_return(false)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false }
end
context 'accepted? returns false and confirmed? returns true' do
before :each do
allow(track).to receive(:accepted?).and_return(false)
allow(track).to receive(:confirmed?).and_return(true)
end
it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false }
end
end
end
end
describe '#create_organizer_role' do
it 'creates the role of the track organizer' do
expect(Role.find_by(name: 'track_organizer', resource: self_organized_track)).to eq nil
self_organized_track.send(:create_organizer_role)
expect(Role.find_by(name: 'track_organizer', resource: self_organized_track).description).to eq 'For the organizers of the Track'
end
it 'is executed when the track is accepted' do
expect(Role.find_by(name: 'track_organizer', resource: self_organized_track)).to eq nil
self_organized_track.accept
expect(Role.find_by(name: 'track_organizer', resource: self_organized_track).description).to eq 'For the organizers of the Track'
end
end
end