module JamRuby class RsvpRequest < ActiveRecord::Base belongs_to :user, :class_name => "JamRuby::User" has_many :rsvp_requests_rsvp_slots, :class_name => "JamRuby::RsvpRequestRsvpSlot", :foreign_key => "rsvp_request_id" 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 # pulls all instruments from the associated rsvp_slots def instrument_list rsvp_slots.map(&:instrument) end def self.index(music_session, user=nil, options={}) query = RsvpRequest .includes(:user) .joins( %Q{ INNER JOIN rsvp_requests_rsvp_slots rrrs ON rrrs.rsvp_request_id = rsvp_requests.id INNER JOIN rsvp_slots rs ON rs.id = rrrs.rsvp_slot_id } ) .where( %Q{ rs.music_session_id = '#{music_session.id}' } ) 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 query = query.where("rsvp_requests.user_id = ?", user.id) unless user.nil? return query.uniq end def self.create(params, user) music_session = MusicSession.find_by_id(params[:session_id]) # verify music session exists if music_session.nil? raise StateError, "Invalid session." end # verify slot IDs exist in request if params[:rsvp_slots].blank? raise StateError, "You must select at least 1 slot." end # verify invitation exists for this user and session invitation = Invitation.where("music_session_id = ? AND receiver_id = ?", music_session.id, user.id) if invitation.first.nil? && !music_session.open_rsvps && music_session.creator.id != user.id raise PermissionError, "Only a session invitee can create an RSVP for this session." end RsvpRequest.transaction do @rsvp = RsvpRequest.new @rsvp.user = user slot_ids = params[:rsvp_slots] instruments = [] # for each slot requested, do the following: # (1) verify slot exists in db # (2) verify slot is not already chosen # (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 # verify slot exists in db if rsvp_slot.nil? raise StateError, "Invalid slot #{id}." end # verify user has not already submitted RSVP request for this slot user_slot = RsvpRequest.joins(:rsvp_requests_rsvp_slots) .where(:user_id => user.id) .where(rsvp_requests_rsvp_slots: {rsvp_slot_id: id}) if !user_slot.blank? raise StateError, "You have already submitted an RSVP request for this slot." end chosen_slot = rsvp_slot.rsvp_requests_rsvp_slots.where("chosen = true").first # verify this slot was not already chosen if !chosen_slot.nil? raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved by the session organizer." else rsvp_request_rsvp_slot = RsvpRequestRsvpSlot.new rsvp_request_rsvp_slot.rsvp_request = @rsvp rsvp_request_rsvp_slot.rsvp_slot = rsvp_slot rsvp_request_rsvp_slot.chosen = true if params[:autoapprove] == true rsvp_request_rsvp_slot.save instruments << rsvp_slot.instrument_id end end @rsvp.save 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]) end Notification.send_scheduled_session_rsvp(music_session, user, instruments) @rsvp end end def self.update(params, user) rsvp_request_id = params[:id] music_session = MusicSession.find_by_id(params[:session_id]) # verify music session exists if music_session.nil? raise StateError, "Invalid session." end # authorize the user attempting to respond to the RSVP request if music_session.creator.id != user.id raise PermissionError, "Only the session organizer can accept or decline and RSVP request." end rsvp_request = RsvpRequest.find_by_id(rsvp_request_id) if rsvp_request.nil? raise StateError, "Invalid RSVP request." end RsvpRequest.transaction do rsvp_responses = params[:rsvp_responses] if !rsvp_responses.blank? instruments = [] 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 if rsvp_slot.chosen && r[:accept] raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved for another user." end if r[:accept] accepted_slot = true request_slot.chosen = true request_slot.save instruments << rsvp_slot.instrument_id else request_slot.chosen = false request_slot.save end end # send notification if at least 1 slot was approved if accepted_slot Notification.send_scheduled_session_rsvp_approved(music_session, rsvp_request.user, instruments) end else raise StateError, "Invalid request." end end end 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 PermissionError, "Only the session organizer or RSVP creator can cancel the RSVP." end RsvpRequest.transaction do 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 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, user) else Notification.send_scheduled_session_rsvp_cancelled(music_session, user) end 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]) 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 end end