| 1 |  |  | class Session < ActiveRecord::Base | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |   has_many :categorizations, :dependent => :destroy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |   has_many :categories, :through => :categorizations | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |   belongs_to :participant  # TODO: rename to 'owner' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |   has_many :presentations, :dependent => :destroy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |   has_many :presenters, :through => :presentations, :source => :participant | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |   belongs_to :event | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |   belongs_to :timeslot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |   belongs_to :room | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |   belongs_to :level | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |   has_many :attendances, :dependent => :destroy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |   has_many :participants, :through => :attendances | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |   delegate :name, to: :room, prefix: true, allow_nil: true | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |   delegate :starts_at, to: :timeslot, allow_nil: true | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |   delegate :name, to: :level, prefix: true, allow_nil: true | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |   scope :with_attendence_count, -> { select('*').joins("LEFT OUTER JOIN (SELECT session_id, count(id) AS attendence_count FROM attendances GROUP BY session_id) AS attendence_aggregation ON attendence_aggregation.session_id = sessions.id") } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |   scope :for_current_event, lambda { where(event_id: Event.current_event.id) } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |   validates_presence_of :description | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |   validates_presence_of :event_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |   validates_presence_of :participant_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |   validates_presence_of :title | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |   validates_length_of :summary, :maximum => 100, :allow_blank => true | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |   #validates_uniqueness_of :timeslot_id, :scope => :room_id, :allow_blank => true, :message => 'and room combination already in use' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |   attr_accessor :name, :email | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |   after_create :create_presenter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |   def self.swap_timeslot_and_rooms(session_1, session_2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |     Session.transaction do | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |       session_1.room, session_2.room = session_2.room, session_1.room | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |       session_1.timeslot, session_2.timeslot = session_2.timeslot, session_1.timeslot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |       session_1.save | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |       session_2.save | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |   def self.swap_rooms(session_1, session_2) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     if session_1.timeslot != session_2.timeslot | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |       raise "Sessions must be in the same timeslot to swap" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     Session.transaction do | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |       session_1.room, session_2.room = session_2.room, session_1.room | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |       session_1.save | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |       session_2.save | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |   def self.attendee_preferences | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |     result = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     sessions = Event.current_event.sessions.includes(:participants) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     sessions.each do |session| | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |       prefs = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |       session.participant_ids.each do |p_id| | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         prefs[p_id] = 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |       end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |       result[session.id] = prefs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |     result | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |   end | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 74 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 75 |  |  |   def self.session_similarity() | 
            
                                                                        
                            
            
                                    
            
            
                | 76 |  |  |     Rails.cache.fetch('session_similarity', :expires_in => 30.minutes) do | 
            
                                                                        
                            
            
                                    
            
            
                | 77 |  |  |       preferences = Session.attendee_preferences | 
            
                                                                        
                            
            
                                    
            
            
                | 78 |  |  |       ::Recommender.calculate_similar_items(preferences, 5) | 
            
                                                                        
                            
            
                                    
            
            
                | 79 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |   def presenter_names | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |     presenters.map(&:name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |   def other_presenters | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |     presenters.reject{ |p| p == self.participant } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |   def other_presenter_names | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |     other_presenters.map(&:name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |   def attending?(user) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |     return false if user.nil? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |     participants.include?(user) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |   def recommended_sessions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |     similarity = Session.session_similarity() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |     recommended = similarity[self.id] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |     if recommended | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |       # find will not order by recommendation strength; use conditions instead of find to ignore missing sessions in the cache | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |       sessions = Session.where(["id in (?)", recommended.map { |r| r[1] }]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |       sessions.sort_by do |session| | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         recommended.find_index { |r| r[1] == session.id } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |       end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     else | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |       [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |   # Estimates actual event-day interest for this session relative to other sessions, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |   # expressed as a corrected number of votes. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |   # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |   # Sessions that were created earlier tend to accumulate more votes, so the naive method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |   # of using raw vote count will underestimate interest in sessions created later. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |   # To fix that, we take the number of votes this session received as a proportion of all | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |   # votes cast since it was created. We also include a normalizing factor for last-minute | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |   # sessions created after most of the voting was already done. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |   # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |   def estimated_interest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |     @estimated_interest ||= begin | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |       session_votes     = attendances.count.to_f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |       possible_votes    = event.attendances.where('attendances.created_at >= ?', created_at).count.to_f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |       session_count     = event.sessions.count.to_f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |       participant_count = event.participants.count.to_f | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |       # For sessions created at the last minute, we don't have enough information to make | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |       # a good estimate; both session_votes and possible_votes are too low. If we just divide | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |       # session_votes / possible_votes, we'll get wildly inaccurate answers when the denominator | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |       # is small. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |       # | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |       # We therefore add some ghost "ballast votes" across the board to all sessions, so as to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |       # make estimated_interest tend toward the mean in cases when there are few real votes. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |       ballast_votes = 3.0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |       (session_votes + ballast_votes) / (possible_votes + ballast_votes * session_count) * participant_count | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |     end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |   def to_h | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |     SessionsJsonBuilder.new.to_hash(self) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |   private | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |   # assign the creator as the first presenter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |   def create_presenter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |     presentations.create(participant: participant) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |   end | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 156 |  |  | end | 
            
                                                        
            
                                    
            
            
                | 157 |  |  |  |