jam-cloud/ruby/lib/jam_ruby/models/rsvp_request.rb

321 lines
11 KiB
Ruby
Raw Normal View History

module JamRuby
class RsvpRequest < ActiveRecord::Base
belongs_to :user, :class_name => "JamRuby::User"
2014-05-21 04:57:32 +00:00
has_many :rsvp_requests_rsvp_slots, :class_name => "JamRuby::RsvpRequestRsvpSlot", :foreign_key => "rsvp_request_id"
2014-05-20 03:34:56 +00:00
has_many :rsvp_slots, :class_name => "JamRuby::RsvpSlot", :through => :rsvp_requests_rsvp_slots
validates :user, presence: true
validates :canceled, :inclusion => {:in => [nil, true, false]}
validate :creator_rsvp_cancel
Merge feature/calendaring branch: commit 8023d6481cbadd52e58b9a4342ac7636ce1807e3 VRFS-3276 : Hook calendar creation into user controller API. Add test to verify. commit 3a35002a46f870e2c490b88b3187e0b1569494fd VRFS-3276 : Calendar cleanup job * Add cleanup method to calendar manager * Create a daily job. * Add calendar cleanup to that job. * Add CRON entry * Daily job/ calendar cleanup test cases * Fix calendar manager spec for new required attribute commit 3ff5910f1f019ae8bcb5afe72a31f1d38bb7d7a3 VRFS-3276 : Add a delete-calendar directive when RSVP is canceled. VRFS-3276 : Include path to partial. This fails depending on the method used to start the web server. commit d2441cbf57e50895ac3b40534873c5d529cb3c4f VRFS-3276 : Test new calendar features. Use icalendar gem in test mode only to more deeply verify calendar in strict mode. commit 9ac272a0fb1e58d8cf9f02e7a0e04caada41f659 VRFS-3276 : Calendar manager updates to include manual calendars. Some refactoring to keep common stuff in one place. commit b5d0c758f0dcae41a5f24635e9da9ce6eda56670 VRFS-3276 : Schema, model updates and new calendar model. commit 20472b6b26c88c04edb9bc698e0c06c549e12eb5 VRFS-3276 : Change initial submit behavior of RSVP dialog to display calendar info. The user can then close the dialog after this prompt. commit 77c99103d0221f20ea342169821b90fa987ecf93 VRFS-3276 : Calendar feed markup and styling. Included as partial. commit e632f48600ae23b5f742773310b2a4ac16ae4ee8 VRFS-3276 : Routes and controller implementation of user calendar ICS feed, which uses calendar manager. commit 21fd80a188eae771a65333566b804ade795a1e8c VRFS-3276 : Initial tests for calendar manager commit 92a2524c65abf7b540f9d50049a1b760a5a9927f VRFS-3276 : Calendar manager * Streamline logic * Enable recurring sessions through rrule * Implement method to create ics feed for user * Extract a type-safe scheduled duration method on music_session for external and internal use. commit b71ad3a4cdd943eb84748abaa85fec263b9af468 VRFS-3276 : Include calendar manager commit f8eaafd03647613dafec9f9422282f8613d08e9a VRFS-3276 : Calendar Manager - initial checkin * Create ICS events given individual parameters * Create calendar from music session * Also will create ICS “delete” events
2015-07-06 20:34:27 +00:00
before_save :cancel_calendar
# pulls all instruments from the associated rsvp_slots
def instrument_list
rsvp_slots.map(&:instrument)
end
def self.index(music_session, user=nil, options={})
2014-05-18 04:09:21 +00:00
query = RsvpRequest
2014-05-21 05:36:32 +00:00
.includes(:user)
2014-05-18 04:09:21 +00:00
.joins(
%Q{
2014-05-20 03:34:56 +00:00
INNER JOIN
rsvp_requests_rsvp_slots rrrs
ON
2014-05-20 03:34:56 +00:00
rrrs.rsvp_request_id = rsvp_requests.id
INNER JOIN
rsvp_slots rs
ON rs.id = rrrs.rsvp_slot_id
}
)
.where(
%Q{
2014-05-21 05:36:32 +00:00
rs.music_session_id = '#{music_session.id}'
}
)
.order('rsvp_requests.created_at DESC')
2014-05-18 04:09:21 +00:00
if options[:status] == 'approved'
query = query.where("rrrs.chosen = true AND canceled != TRUE")
elsif options[:status] == 'pending'
query = query.where("rrrs.chosen is null AND canceled != TRUE")
end
2014-05-21 05:36:32 +00:00
query = query.where("rsvp_requests.user_id = ?", user.id) unless user.nil?
2014-05-21 04:57:32 +00:00
return query.uniq
2014-05-18 04:09:21 +00:00
end
def self.create(params, user)
2014-05-21 21:47:11 +00:00
music_session = MusicSession.find_by_id(params[:session_id])
2014-05-21 04:57:32 +00:00
# verify music session exists
if music_session.nil?
2014-05-22 03:36:34 +00:00
raise StateError, "Invalid session."
2014-05-21 04:57:32 +00:00
end
2014-06-07 17:01:03 +00:00
# verify slot IDs exist in request
if params[:rsvp_slots].blank?
raise StateError, "You must select at least 1 slot."
end
2014-05-21 04:57:32 +00:00
# verify invitation exists for this user and session
2014-05-21 05:36:32 +00:00
invitation = Invitation.where("music_session_id = ? AND receiver_id = ?", music_session.id, user.id)
2014-05-21 04:57:32 +00:00
if invitation.first.nil? && !music_session.open_rsvps && music_session.creator.id != user.id
raise JamPermissionError, "Only a session invitee can create an RSVP for this session."
2014-05-21 04:57:32 +00:00
end
RsvpRequest.transaction do
2014-05-21 04:57:32 +00:00
@rsvp = RsvpRequest.new
2014-05-21 21:47:11 +00:00
@rsvp.user = user
2014-05-21 04:57:32 +00:00
slot_ids = params[:rsvp_slots]
2014-05-29 03:43:57 +00:00
2014-05-21 04:57:32 +00:00
instruments = []
# for each slot requested, do the following:
# (1) verify slot exists in db
# (2) verify slot is not already chosen
2014-05-22 03:36:34 +00:00
# (3) verify user has not already requested this slot
# (4) create RsvpRequestRsvpSlot
# (5) create RsvpRequest
# special case: if the slot is the value 'unstructured',
# we will also on-demand create a RsvpSlot.
slot_ids.each do |id|
if id == "unstructured"
rsvp_slot = RsvpSlot.new
rsvp_slot.is_unstructured_rsvp = true
rsvp_slot.music_session = music_session
unless rsvp_slot.save
raise StateError, 'Unable to auto-create RSVP Slot'
end
else
rsvp_slot = RsvpSlot.where(:id => id).first
end
2014-05-21 04:57:32 +00:00
# verify slot exists in db
if rsvp_slot.nil?
2014-05-22 03:36:34 +00:00
raise StateError, "Invalid slot #{id}."
end
# verify user has not already submitted RSVP request for this slot
rsvp = RsvpRequest.joins(:rsvp_requests_rsvp_slots)
2014-05-22 03:36:34 +00:00
.where(:user_id => user.id)
2014-08-10 03:22:17 +00:00
.where(:canceled => false)
2014-05-22 03:36:34 +00:00
.where(rsvp_requests_rsvp_slots: {rsvp_slot_id: id})
2014-08-10 03:22:17 +00:00
if !rsvp.blank?
2014-05-22 03:36:34 +00:00
raise StateError, "You have already submitted an RSVP request for this slot."
2014-05-21 04:57:32 +00:00
end
chosen_slot = rsvp_slot.rsvp_requests_rsvp_slots.where("chosen = true").first
# verify this slot was not already chosen
if !chosen_slot.nil?
2014-05-22 03:36:34 +00:00
raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved by the session organizer."
2014-05-21 04:57:32 +00:00
else
rsvp_request_rsvp_slot = RsvpRequestRsvpSlot.new
2014-05-21 21:47:11 +00:00
rsvp_request_rsvp_slot.rsvp_request = @rsvp
2014-05-21 04:57:32 +00:00
rsvp_request_rsvp_slot.rsvp_slot = rsvp_slot
rsvp_request_rsvp_slot.chosen = true if params[:autoapprove] == true
2014-05-21 04:57:32 +00:00
rsvp_request_rsvp_slot.save
instruments << rsvp_slot.instrument_id
end
end
2014-05-21 04:57:32 +00:00
@rsvp.save
2014-05-21 21:47:11 +00:00
unless params[:message].blank?
session_info_comment = SessionInfoComment.new
session_info_comment.music_session = music_session
session_info_comment.user = user
session_info_comment.comment = params[:message]
session_info_comment.save
Notification.send_scheduled_session_comment(music_session, user, params[:message])
2014-05-21 21:47:11 +00:00
end
2014-05-21 04:57:32 +00:00
Notification.send_scheduled_session_rsvp(music_session, user, instruments)
@rsvp
end
end
2014-05-21 04:57:32 +00:00
def self.update(params, user)
rsvp_request_id = params[:id]
2014-05-22 03:36:34 +00:00
music_session = MusicSession.find_by_id(params[:session_id])
2014-05-21 04:57:32 +00:00
# verify music session exists
if music_session.nil?
2014-05-22 03:36:34 +00:00
raise StateError, "Invalid session."
2014-05-21 04:57:32 +00:00
end
2014-05-21 04:57:32 +00:00
# authorize the user attempting to respond to the RSVP request
if music_session.creator.id != user.id
raise JamPermissionError, "Only the session organizer can accept or decline an RSVP request."
2014-05-21 04:57:32 +00:00
end
2014-05-22 03:36:34 +00:00
rsvp_request = RsvpRequest.find_by_id(rsvp_request_id)
if rsvp_request.nil?
raise StateError, "Invalid RSVP request."
end
2014-05-21 04:57:32 +00:00
RsvpRequest.transaction do
2014-05-22 03:36:34 +00:00
rsvp_responses = params[:rsvp_responses]
if !rsvp_responses.blank?
2014-05-21 04:57:32 +00:00
instruments = []
2014-05-22 03:36:34 +00:00
accepted_slot = false
rsvp_responses.each do |r|
request_slot_id = r[:request_slot_id]
request_slot = RsvpRequestRsvpSlot.find_by_id(request_slot_id)
if request_slot.nil?
raise StateError, "Invalid request slot #{request_slot_id}."
end
rsvp_slot = RsvpSlot.find_by_id(request_slot.rsvp_slot_id)
if rsvp_slot.nil?
raise StateError, "Slot does not exist"
end
# slot has already been accepted
2014-06-13 07:45:45 +00:00
if rsvp_slot.chosen && r[:accept]
# get the instrument and skill level for this slot and see if there are others available
# and auto-reassign the request_slot to the open rsvp_slot
open_slots = music_session.open_slots
# don't worry about matching proficiency if the user RSVPed to "Any Skill Level"
if rsvp_slot.proficiency_level == 0
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id }
else
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id && slot.proficiency_level == rsvp_slot.proficiency_level }
end
# (1) another available slot exists matching this instrument and proficiency
unless open_slots.blank?
rsvp_slot = open_slots.first
request_slot.rsvp_slot_id = rsvp_slot.id # this links the RsvpRequestRsvpSlot to the available open slot matching this instrument and proficiency level
# (2) no identical slots available => create a new one on the fly
else
new_slot = RsvpSlot.new
new_slot.instrument_id = rsvp_slot.instrument_id
new_slot.proficiency_level = rsvp_slot.proficiency_level
new_slot.music_session_id = rsvp_slot.music_session_id
new_slot.is_unstructured_rsvp = rsvp_slot.is_unstructured_rsvp
new_slot.save!
request_slot.rsvp_slot_id = new_slot.id # saved below on line 218
end
2014-05-22 03:36:34 +00:00
end
2014-05-21 04:57:32 +00:00
2014-05-22 03:36:34 +00:00
if r[:accept]
accepted_slot = true
2014-05-21 04:57:32 +00:00
request_slot.chosen = true
request_slot.save
instruments << rsvp_slot.instrument_id
2014-05-22 03:36:34 +00:00
else
request_slot.chosen = false
request_slot.save
2014-05-21 04:57:32 +00:00
end
end
2014-05-22 03:36:34 +00:00
# send notification if at least 1 slot was approved
if accepted_slot
Notification.send_scheduled_session_rsvp_approved(music_session, rsvp_request.user, instruments)
2014-05-22 03:36:34 +00:00
end
2014-05-21 04:57:32 +00:00
else
2014-05-22 03:36:34 +00:00
raise StateError, "Invalid request."
2014-05-21 04:57:32 +00:00
end
end
end
2014-05-22 04:40:17 +00:00
def self.cancel(params, user)
if params[:id].blank?
raise StateError, "RSVP request ID is required."
end
if params[:session_id].blank?
raise StateError, "Session ID is required."
end
music_session = MusicSession.find(params[:session_id])
rsvp_request = RsvpRequest.find(params[:id])
if music_session.creator.id != user.id && rsvp_request.user_id != user.id
raise JamPermissionError, "Only the session organizer or RSVP creator can cancel the RSVP."
2014-05-21 04:57:32 +00:00
end
RsvpRequest.transaction do
2014-05-22 04:40:17 +00:00
case params[:cancelled]
when 'yes'
rsvp_request.canceled = true
rsvp_request.cancel_all = false
when 'all'
rsvp_request.canceled = true
rsvp_request.cancel_all = true
end
rsvp_request.save
if rsvp_request.errors.any?
return rsvp_request
end
# mark corresponding slot's chosen field as false
2014-05-22 04:40:17 +00:00
rsvp_request_slots = RsvpRequestRsvpSlot.where("rsvp_request_id = ?", rsvp_request.id)
rsvp_request_slots.each do |slot|
if slot.chosen
slot.chosen = false
slot.save
end
end
# send notification
if music_session.creator.id == user.id
Notification.send_scheduled_session_rsvp_cancelled_org(music_session, rsvp_request.user)
else
Notification.send_scheduled_session_rsvp_cancelled(music_session, user)
end
2014-05-22 04:40:17 +00:00
unless params[:message].blank?
session_info_comment = SessionInfoComment.new
session_info_comment.music_session = music_session
session_info_comment.user = user
session_info_comment.comment = params[:message]
session_info_comment.save
Notification.send_scheduled_session_comment(music_session, user, params[:message], true)
2014-05-22 04:40:17 +00:00
end
end
end
private
def creator_rsvp_cancel
if canceled && !canceled_was && user == self.rsvp_slots[0].music_session.creator
errors.add(:canceled, "can't be canceled by the session organizer")
end
end
Merge feature/calendaring branch: commit 8023d6481cbadd52e58b9a4342ac7636ce1807e3 VRFS-3276 : Hook calendar creation into user controller API. Add test to verify. commit 3a35002a46f870e2c490b88b3187e0b1569494fd VRFS-3276 : Calendar cleanup job * Add cleanup method to calendar manager * Create a daily job. * Add calendar cleanup to that job. * Add CRON entry * Daily job/ calendar cleanup test cases * Fix calendar manager spec for new required attribute commit 3ff5910f1f019ae8bcb5afe72a31f1d38bb7d7a3 VRFS-3276 : Add a delete-calendar directive when RSVP is canceled. VRFS-3276 : Include path to partial. This fails depending on the method used to start the web server. commit d2441cbf57e50895ac3b40534873c5d529cb3c4f VRFS-3276 : Test new calendar features. Use icalendar gem in test mode only to more deeply verify calendar in strict mode. commit 9ac272a0fb1e58d8cf9f02e7a0e04caada41f659 VRFS-3276 : Calendar manager updates to include manual calendars. Some refactoring to keep common stuff in one place. commit b5d0c758f0dcae41a5f24635e9da9ce6eda56670 VRFS-3276 : Schema, model updates and new calendar model. commit 20472b6b26c88c04edb9bc698e0c06c549e12eb5 VRFS-3276 : Change initial submit behavior of RSVP dialog to display calendar info. The user can then close the dialog after this prompt. commit 77c99103d0221f20ea342169821b90fa987ecf93 VRFS-3276 : Calendar feed markup and styling. Included as partial. commit e632f48600ae23b5f742773310b2a4ac16ae4ee8 VRFS-3276 : Routes and controller implementation of user calendar ICS feed, which uses calendar manager. commit 21fd80a188eae771a65333566b804ade795a1e8c VRFS-3276 : Initial tests for calendar manager commit 92a2524c65abf7b540f9d50049a1b760a5a9927f VRFS-3276 : Calendar manager * Streamline logic * Enable recurring sessions through rrule * Implement method to create ics feed for user * Extract a type-safe scheduled duration method on music_session for external and internal use. commit b71ad3a4cdd943eb84748abaa85fec263b9af468 VRFS-3276 : Include calendar manager commit f8eaafd03647613dafec9f9422282f8613d08e9a VRFS-3276 : Calendar Manager - initial checkin * Create ICS events given individual parameters * Create calendar from music session * Also will create ICS “delete” events
2015-07-06 20:34:27 +00:00
def cancel_calendar
calendar_manager = CalendarManager.new
if self.canceled
self.rsvp_slots.each do |slot|
calendar_manager.cancel_ics_event(slot.music_session, user)
end
end
end
end
end