diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9102e7883..517b2ee9d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -143,4 +143,12 @@ def upcoming_workshops end helper_method :upcoming_workshops + + def redirect_back(fallback_location:, **args) + if referer = request.headers["Referer"] + redirect_to referer, **args + else + redirect_to fallback_location, **args + end + end end diff --git a/app/controllers/concerns/invitation_controller_concerns.rb b/app/controllers/concerns/invitation_controller_concerns.rb index 82e6980fb..c9844fa95 100644 --- a/app/controllers/concerns/invitation_controller_concerns.rb +++ b/app/controllers/concerns/invitation_controller_concerns.rb @@ -10,26 +10,30 @@ module InvitationControllerConcerns module InstanceMethods def accept if @invitation.attending? - redirect_to :back, notice: t('messages.already_rsvped') + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.already_rsvped')) end user = current_user || @invitation.member if user.has_existing_RSVP_on(@invitation.workshop.date_and_time) - return redirect_to :back, notice: t('messages.invitations.rsvped_to_other_workshop') + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.invitations.rsvped_to_other_workshop')) end @workshop = WorkshopPresenter.new(@invitation.workshop) if (@invitation.for_student? && @workshop.student_spaces?) || (@invitation.for_coach? && @workshop.coach_spaces?) @invitation.update_attributes(attending: true, rsvp_time: Time.zone.now) @invitation.waiting_list.destroy if @invitation.waiting_list.present? - WorkshopInvitationMailer.attending(@invitation.workshop, @invitation.member, @invitation).deliver_now - - redirect_to :back, notice: t('messages.accepted_invitation', - name: @invitation.member.name) + WorkshopInvitationMailer.attending(@invitation.workshop, + @invitation.member, + @invitation).deliver_now + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.accepted_invitation', name: @invitation.member.name)) else - redirect_to :back, notice: t('messages.no_available_seats', email: @invitation.workshop.chapter.email) + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.no_available_seats', email: @invitation.workshop.chapter.email)) end end @@ -37,7 +41,8 @@ def reject if @invitation.parent.date_and_time - 3.5.hours >= Time.zone.now if @invitation.attending.eql? false - redirect_to :back, notice: t('messages.not_attending_already') + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.not_attending_already')) else @invitation.update_attribute(:attending, false) @@ -47,13 +52,17 @@ def reject invitation = next_spot.invitation next_spot.destroy invitation.update_attribute(:attending, true) - WorkshopInvitationMailer.attending(invitation.workshop, invitation.member, invitation, true).deliver_now + WorkshopInvitationMailer.attending(invitation.workshop, + invitation.member, + invitation, true).deliver_now end - redirect_to :back, notice: t('messages.rejected_invitation', name: @invitation.member.name) + return redirect_back(fallback_location: invitation_path(@invitation), + notice: t('messages.rejected_invitation', name: @invitation.member.name)) end else - redirect_to :back, notice: 'You can only change your RSVP status up to 3.5 hours before the workshop' + return redirect_back(fallback_location: invitation_path(@invitation), + notice: 'You can only change your RSVP status up to 3.5 hours before the workshop') end end end diff --git a/spec/features/accepting_invitation_spec.rb b/spec/features/accepting_invitation_spec.rb index 31f826883..4c0bbc6ec 100644 --- a/spec/features/accepting_invitation_spec.rb +++ b/spec/features/accepting_invitation_spec.rb @@ -2,8 +2,11 @@ feature 'a member can' do context '#workshop' do - let(:invitation) { Fabricate(:workshop_invitation) } + let(:member) { Fabricate(:member) } + let(:invitation) { Fabricate(:workshop_invitation, member: member) } let(:invitation_route) { invitation_path(invitation) } + let(:accept_invitation_route) { accept_invitation_path(invitation) } + let(:reject_invitation_route) { reject_invitation_path(invitation) } let(:member) { Fabricate(:member) } let(:set_no_available_slots) { invitation.workshop.host.update_attribute(:seats, 0) } diff --git a/spec/features/coach_accepting_invitation_spec.rb b/spec/features/coach_accepting_invitation_spec.rb index 60b38e118..6ed0cec3f 100644 --- a/spec/features/coach_accepting_invitation_spec.rb +++ b/spec/features/coach_accepting_invitation_spec.rb @@ -3,8 +3,10 @@ feature 'a Coach can' do context '#workshop' do let(:member) { Fabricate(:member) } - let(:invitation) { Fabricate(:coach_workshop_invitation) } + let(:invitation) { Fabricate(:coach_workshop_invitation, member: member) } let(:invitation_route) { invitation_path(invitation) } + let(:reject_invitation_route) { reject_invitation_path(invitation) } + let(:accept_invitation_route) { accept_invitation_path(invitation) } let(:set_no_available_slots) { invitation.workshop.host.update_attribute(:seats, 0) } diff --git a/spec/support/shared_examples/behaves_like_an_invitation_route.rb b/spec/support/shared_examples/behaves_like_an_invitation_route.rb index fc260643b..66c257af9 100644 --- a/spec/support/shared_examples/behaves_like_an_invitation_route.rb +++ b/spec/support/shared_examples/behaves_like_an_invitation_route.rb @@ -7,6 +7,24 @@ expect(page).to have_link 'I can no longer attend' expect(page).to have_content("Thanks for getting back to us #{invitation.member.name}.") + expect(page.current_path).to eq(invitation_route) + end + + scenario 'they can RSVP directly through the invitation' do + Tutorial.create(title: 'title') + visit accept_invitation_route + + expect(page).to have_link 'I can no longer attend' + expect(page.current_path).to eq(invitation_route) + expect(page).to have_content(I18n.t('messages.accepted_invitation', name: member.name)) + end + + scenario 'when they have already RSVPed and are attempting to re-accept through the invitation link' do + invitation.update_attribute(:attending, true) + visit accept_invitation_route + + expect(current_url).to eq(invitation_url(invitation)) + expect(page).to have_content(I18n.t('messages.already_rsvped')) end scenario 'when there are no available spots' do @@ -16,6 +34,14 @@ expect(current_url).to eq(invitation_url(invitation)) expect(page).to have_content('The workshop is full') end + + scenario 'when there are no available spots and they accept through the invitation link' do + set_no_available_slots + visit accept_invitation_route + + expect(current_url).to eq(invitation_url(invitation)) + expect(page).to have_content('The workshop is full') + end end context 'unable to attend' do @@ -27,7 +53,15 @@ expect(page).to have_content(I18n.t('messages.rejected_invitation', name: invitation.member.name)) end - scenario 'when already confirmed' do + scenario 'when they are successful by accessing the link directly' do + invitation.update_attribute(:attending, true) + visit reject_invitation_route + + expect(page).to have_content(I18n.t('messages.rejected_invitation', name: invitation.member.name)) + expect(page.current_path).to eq(invitation_route) + end + + scenario 'when already confirmed they are not attending' do invitation.update_attribute(:attending, false) visit invitation_route @@ -35,6 +69,14 @@ expect(page).to_not have_content 'I can no longer attend' end + scenario 'when already confirmed they are not attending and reject by accessing the link directly' do + invitation.update_attribute(:attending, false) + visit reject_invitation_route + + expect(page).to have_content(I18n.t('messages.not_attending_already')) + expect(page.current_path).to eq(invitation_route) + end + scenario 'when already RSVPd to another event on same evening' do invitation.update_attributes(attending: true, member_id: member.id) @@ -44,9 +86,36 @@ visit invitation2_route click_on 'Attend' - expect(page).to have_content("You have already RSVP'd to another workshop on this date. If you would prefer to attend this workshop, please cancel your other RSVP first.") + expect(page).to have_content(I18n.t('messages.invitations.rsvped_to_other_workshop')) expect(page).to have_selector(:link_or_button, 'Attend') end + + scenario 'when already RSVPd to another event on same evening and attempting to RSVP directly through the link' do + invitation.update_attributes(attending: true, member_id: member.id) + + invitation2 = Fabricate(:coach_workshop_invitation) + invitation2_route = invitation_path(invitation2) + + visit accept_invitation_path(invitation2) + + expect(page).to have_content(I18n.t('messages.invitations.rsvped_to_other_workshop')) + end + + scenario 'when the event is less than 3.5 hours from now' do + invitation.workshop.update_attribute(:date_and_time, Time.zone.now + 3.hours) + visit reject_invitation_route + + expect(page).to have_content('You can only change your RSVP status up to 3.5 hours before the workshop') + expect(page.current_path).to eq(invitation_route) + end + + scenario 'when the event is less than 3.5 hours from now and tje reject by accessing the link directly' do + invitation.workshop.update_attribute(:date_and_time, Time.zone.now + 3.hours) + visit reject_invitation_route + + expect(page).to have_content('You can only change your RSVP status up to 3.5 hours before the workshop') + expect(page.current_path).to eq(invitation_route) + end end context 'waiting list' do