module JamRuby class MusicSession < ActiveRecord::Base NO_RECURRING = 'once' RECURRING_WEEKLY = 'weekly' RECURRING_MODES = [NO_RECURRING, RECURRING_WEEKLY] attr_accessor :legal_terms, :recurring_mode self.table_name = "music_sessions" self.primary_key = 'id' belongs_to :creator,:class_name => 'JamRuby::User', :foreign_key => :user_id, :inverse_of => :music_session_histories belongs_to :band, :class_name => 'JamRuby::Band', :foreign_key => :band_id, :inverse_of => :music_sessions belongs_to :active_music_session, :class_name => 'JamRuby::ActiveMusicSession', foreign_key: :music_session_id has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id", :dependent => :delete_all has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id" has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "session_id" has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id' has_one :feed, :class_name => "JamRuby::Feed", :inverse_of => :music_session, :foreign_key => 'music_session_id', :dependent => :destroy belongs_to :genre, :class_name => "JamRuby::Genre", :inverse_of => :music_sessions, :foreign_key => 'genre_id' has_many :join_requests, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::JoinRequest", :foreign_key => "music_session_id" has_many :invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::Invitation", :foreign_key => "music_session_id" has_many :invited_musicians, :through => :invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver has_many :fan_invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::FanInvitation", :foreign_key => "music_session_id" has_many :invited_fans, :through => :fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver validates :genre, :presence => true validates :description, :presence => true, :no_profanity => true validates :fan_chat, :inclusion => {:in => [true, false]} validates :fan_access, :inclusion => {:in => [true, false]} validates :approval_required, :inclusion => {:in => [true, false]} validates :musician_access, :inclusion => {:in => [true, false]} validates :legal_terms, :inclusion => {:in => [true]}, :on => :create validates :creator, :presence => true # validates :recurring_mode, :inclusion => {:in => RECURRING_MODES}, :on => :create validate :creator_is_musician before_create :generate_share_token before_create :add_to_feed SHARE_TOKEN_LENGTH = 8 SEPARATOR = '|' def add_to_feed feed = Feed.new feed.music_session = self end def comment_count self.comments.size end def grouped_tracks tracks = [] self.music_session_user_histories.each do |msuh| user = User.find(msuh.user_id) t = Track.new t.musician = user t.instrument_ids = [] # this treats each track as a "user", which has 1 or more instruments in the session unless msuh.instruments.blank? instruments = msuh.instruments.split(SEPARATOR) instruments.each do |instrument| if !t.instrument_ids.include? instrument t.instrument_ids << instrument end end end tracks << t end tracks end def self.index(current_user, user_id, band_id = nil, genre = nil) hide_private = false if current_user.id != user_id hide_private = false # TODO: change to true once public flag exists end query = MusicSession .joins( %Q{ LEFT OUTER JOIN music_sessions_user_history ON music_sessions.id = music_sessions_user_history.music_session_id } ) .where( %Q{ music_sessions.user_id = '#{user_id}' } ) #query = query.where("public = false") unless !hide_private query = query.where("music_sessions.band_id = '#{band_id}") unless band_id.nil? query = query.where("music_sessions.genres like '%#{genre}%'") unless genre.nil? return query end def self.create user, params band = Band.find(params[:band]) unless params[:band].nil? ms = MusicSession.new ms.name = params[:description][0..40] ms.description = params[:description] ms.musician_access = params[:musician_access] ms.approval_required = params[:approval_required] ms.fan_access = params[:fan_access] ms.fan_chat = params[:fan_chat] ms.band = band ms.legal_policy = params[:legal_policy] ms.language = params[:language] ms.genre_id = (params[:genres].length > 0 ? params[:genres][0] : nil) if params[:genres] ms.legal_terms = true ms.creator = user ms.save end def unique_users User .joins(:music_session_user_histories) .group("users.id") .order("users.id") .where(%Q{ music_sessions_user_history.music_session_id = '#{id}'}) end # returns one user history per user, with instruments all crammed together, and with total duration def unique_user_histories MusicSessionUserHistory .joins(:user) .select("STRING_AGG(instruments, '|') AS total_instruments, SUM(date_part('epoch', COALESCE(music_sessions_user_history.session_removed_at, music_sessions_user_history.created_at) - music_sessions_user_history.created_at)) AS total_duration, music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url") .group("music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url") .order("music_sessions_user_history.user_id") .where(%Q{ music_sessions_user_history.music_session_id = '#{id}'}) end def duration_minutes end_time = self.session_removed_at || Time.now (end_time - self.created_at) / 60.0 end def music_session_user_histories @msuh ||= JamRuby::MusicSessionUserHistory .where(:music_session_id => self.id) .order('created_at DESC') end def comments @comments ||= JamRuby::MusicSessionComment .where(:music_session_id => self.id) .order('created_at DESC') end def likes @likes ||= JamRuby::MusicSessionLiker .where(:music_session_id => self.music_session_id) end # these are 'users that are a part of this session' # which means are currently in the music_session, or, rsvp'ed, or creator def part_of_session? user # XXX check RSVP'ed user == self.creator || (active_music_session ? active_music_session.users.exists?(user) : false) end def is_over? active_music_session.nil? end def has_mount? active_music_session && active_music_session.mount end def recordings Recording.where(music_session_id: self.id) end def end_history self.update_attribute(:session_removed_at, Time.now) # ensure all user histories are closed music_session_user_histories.each do |music_session_user_history| music_session_user_history.end_history # then update any users that need their user progress updated if music_session_user_history.duration_minutes > 15 && music_session_user_history.max_concurrent_connections >= 3 music_session_user_history.user.update_progression_field(:first_real_music_session_at) end end end def self.removed_music_session(session_id) hist = self .where(:id => session_id) .limit(1) .first hist.end_history if hist Notification.send_session_ended(session_id) end def remove_non_alpha_num(token) token.gsub(/[^0-9A-Za-z]/, '') end private def generate_share_token token = loop do token = SecureRandom.urlsafe_base64(SHARE_TOKEN_LENGTH, false) token = remove_non_alpha_num(token) token.upcase! break token unless ShareToken.exists?(token: token) end self.share_token = ShareToken.new self.share_token.token = token self.share_token.shareable_type = "session" end def creator_is_musician unless creator && creator.musician? errors.add(:creator, ValidationMessages::MUST_BE_A_MUSICIAN) end end end end