Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
$(function() {
$("body").removeClass("no-js");

$('#event_local_date, #meeting_local_date, #workshop_local_date, #workshop_rsvp_open_local_date').pickadate({
$('#event_local_date, #meeting_local_date, #workshop_local_date, #workshop_rsvp_open_local_date, #workshop_rsvp_close_local_date').pickadate({
format: 'dd/mm/yyyy'
});
$('#announcement_expires_at, #ban_expires_at').pickadate();
$(
"#meeting_local_time, #meeting_local_end_time, #event_local_time, #event_local_end_time, #workshop_local_time, #workshop_local_end_time, #workshop_rsvp_open_local_time"
"#meeting_local_time, #meeting_local_end_time, #event_local_time, #event_local_end_time, #workshop_local_time, #workshop_local_end_time, #workshop_rsvp_open_local_time, #workshop_rsvp_close_local_time"
).pickatime({
format: "HH:i",
});
Expand Down
1 change: 1 addition & 0 deletions app/controllers/admin/workshops_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def workshop_params
:local_date, :local_time, :local_end_time, :chapter_id,
:invitable, :seats, :virtual, :slack_channel, :slack_channel_link,
:rsvp_open_local_date, :rsvp_open_local_time, :description,
:rsvp_close_local_date, :rsvp_close_local_time,
:coach_spaces, :student_spaces,
{ sponsor_ids: [] }
])
Expand Down
1 change: 1 addition & 0 deletions app/controllers/workshop_invitation_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def accept
user = current_user || @invitation.member
workshop = @invitation.workshop
return back_with_message(t('messages.already_rsvped')) if @invitation.attending?
return back_with_message(t('messages.invitations.closed')) unless workshop.rsvp_available?

@invitation.assign_attributes(invitation_params.merge!(attending: true, rsvp_time: Time.zone.now))
return back_with_message(@invitation.errors.full_messages) unless @invitation.valid?
Expand Down
24 changes: 22 additions & 2 deletions app/models/workshop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ class Workshop < ApplicationRecord
include Invitable
include Listable

attr_accessor :local_date, :local_time, :local_end_time, :rsvp_open_local_date, :rsvp_open_local_time
attr_accessor :local_date, :local_time, :local_end_time, :rsvp_open_local_date, :rsvp_open_local_time,
:rsvp_close_local_date, :rsvp_close_local_time

resourcify :permissions, role_cname: 'Permission', role_table_name: :permission

Expand Down Expand Up @@ -34,6 +35,8 @@ class Workshop < ApplicationRecord

before_validation :set_date_and_time, :set_end_date_and_time, if: proc { |model| model.chapter_id.present? }
before_validation :set_opens_at
before_validation :set_closes_at
validate :rsvp_close_before_workshop_start

def host
workshop_host&.sponsor
Expand Down Expand Up @@ -78,7 +81,7 @@ def invitable_yet?
end

def available_for_rsvp?
invitable_yet? && date_and_time.future?
invitable_yet? && rsvp_available?
end

# Is this person attending this event?
Expand Down Expand Up @@ -117,10 +120,27 @@ def rsvp_opens_at
super.in_time_zone(time_zone)
end

def rsvp_closes_at
return nil unless super

super.in_time_zone(time_zone)
end

private

def set_opens_at
new_opens_at = datetime_from_fields(rsvp_open_local_date, rsvp_open_local_time)
self.rsvp_opens_at = new_opens_at if new_opens_at
end

def set_closes_at
new_closes_at = datetime_from_fields(rsvp_close_local_date, rsvp_close_local_time)
self.rsvp_closes_at = new_closes_at if new_closes_at
end

def rsvp_close_before_workshop_start
return unless rsvp_closes_at && date_and_time
return if rsvp_closes_at < date_and_time
errors.add(:rsvp_close_local_date, "must be before the workshop start time")
end
end
15 changes: 12 additions & 3 deletions app/views/admin/workshops/_shared_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
.col-12
.card.bg-light.border-info.mb-3
.card-body
%p= t('admin.workshop.form.rsvp_details')
= f.input :rsvp_open_local_date, as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:strftime, '%d/%m/%Y') } }
= f.input :rsvp_open_local_time, as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:time).try(:strftime, '%H:%M') } }
%h6.card-title RSVP Timing
%p.small.text-muted= t('admin.workshop.form.rsvp_details')
.row
.col-12.col-md-6
= f.input :rsvp_open_local_date, label: 'Open date', as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:strftime, '%d/%m/%Y') } }
.col-12.col-md-6
= f.input :rsvp_open_local_time, label: 'Open time', as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:time).try(:strftime, '%H:%M') } }
.row
.col-12.col-md-6
= f.input :rsvp_close_local_date, label: 'Close date', as: :string, input_html: { data: { value: @workshop.rsvp_closes_at.try(:strftime, '%d/%m/%Y') } }
.col-12.col-md-6
= f.input :rsvp_close_local_time, label: 'Close time', as: :string, input_html: { data: { value: @workshop.rsvp_closes_at.try(:time).try(:strftime, '%H:%M') } }
4 changes: 4 additions & 0 deletions app/views/admin/workshops/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
- else
RSVPs will open at
= @workshop.rsvp_opens_at.strftime('%H:%M on %d/%m/%Y.')
- if @workshop.rsvp_closes_at
%div.mb-2
RSVPs will close at
= @workshop.rsvp_closes_at.strftime('%H:%M on %d/%m/%Y.')
- if @workshop.venue.present? || @workshop.virtual?
%span.badge.bg-info #{@workshop.student_spaces} student spots, #{@workshop.coach_spaces} coach spots
- unless @workshop.spaces?
Expand Down
3 changes: 2 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ en:
spot_confirmed: "Your spot has been confirmed for %{event}! We look forward to seeing you there."
spot_not_confirmed: "Your spot has not yet been confirmed. We will verify your attendance after you complete the questionnaire."
updated_details: "Invitation details successfully updated."
closed: "RSVPs for this workshop are now closed."
invalid_format: "The requested format is invalid: %{invalid_format}"
notifications:
provider_already_connected: "You are already signed in!"
Expand Down Expand Up @@ -665,7 +666,7 @@ en:
failure: "Workshop cannot be deleted. This is because it has invitees and/or workshop information is on the website for a while long enough that it cannot be deleted."
form:
virtual_info: To create a virtual workshop you must check the box and fill in the below fields. The slack channel will be available on the invitation page for anyone who successfuly RSVPs.
rsvp_details: Fill out these fields if you want RSVPs to open automatically at a future time. Leave blank if you'll handle it manually later.
rsvp_details: Set a date and time (in the chapter's timezone) for RSVPs to open and close automatically. Leave blank to handle manually.
not_invitable: "The workshop is not invitable"
virtual:
details:
Expand Down
8 changes: 8 additions & 0 deletions spec/controllers/admin/workshops_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
end
end

describe 'POST #create' do
it 'permits rsvp_close_local_date and rsvp_close_local_time' do
expect do
post :create, params: { workshop: { rsvp_close_local_date: '01/12/2020', rsvp_close_local_time: '15:00', host: '' } }
end.not_to raise_error
end
end

describe 'DELETE #destroy' do
context 'workshop invitations have been sent' do
before do
Expand Down
12 changes: 12 additions & 0 deletions spec/features/accepting_invitation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@

it_behaves_like 'invitation route'

context 'when RSVPs are closed' do
scenario 'cannot accept an invitation after the close time' do
invitation.workshop.update(rsvp_closes_at: 1.hour.ago)

visit invitation_route
click_on 'Attend'

expect(page).to have_content('RSVPs for this workshop are now closed.')
expect(invitation.reload.attending).not_to be(true)
end
end

context 'amend invitation details' do
context 'a student' do
scenario 'cannot accept an invitation without a tutorial' do
Expand Down
40 changes: 40 additions & 0 deletions spec/models/workshop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@
it { is_expected.to validate_numericality_of(:student_spaces).is_greater_than(0) }
it { is_expected.to validate_numericality_of(:coach_spaces).is_greater_than(0) }
end

context '#rsvp_closes_at' do
it 'must be before the workshop start time' do
workshop.date_and_time = Time.zone.now + 1.hour
workshop.rsvp_closes_at = Time.zone.now + 2.hours

workshop.valid?
expect(workshop.errors[:rsvp_close_local_date]).to include("must be before the workshop start time")
end

it 'is valid when close time is before workshop start' do
workshop.date_and_time = Time.zone.now + 2.hours
workshop.rsvp_closes_at = Time.zone.now + 1.hour

expect(workshop.valid?).to be(true)
end

it 'is valid when no close time is set' do
workshop.rsvp_closes_at = nil
expect(workshop.valid?).to be(true)
end
end
end

context 'time zone fields' do
Expand Down Expand Up @@ -87,6 +109,24 @@
expect(workshop.rsvp_opens_at.zone).to eq('PDT')
end
end

context 'rsvp_closes_at' do
it 'saves the local time in UTC' do
workshop.update!(
rsvp_close_local_date: '12/06/2015',
rsvp_close_local_time: '18:30'
)

expect(workshop.read_attribute(:rsvp_closes_at)).to eq(utc_time)
end

it 'retrieves the local time from the saved UTC value' do
workshop.update_attribute(:rsvp_closes_at, utc_time)

expect(workshop.rsvp_closes_at).to eq(pacific_time)
expect(workshop.rsvp_closes_at.zone).to eq('PDT')
end
end
end

context '#rsvp_available?' do
Expand Down