module JamRuby class Band < ActiveRecord::Base attr_accessible :name, :website, :biography, :city, :state, :country, :original_fpfile_photo, :cropped_fpfile_photo, :cropped_s3_path_photo, :crop_selection_photo, :photo_url attr_accessor :updating_photo self.primary_key = 'id' before_save :stringify_photo_info , :if => :updating_photo validate :validate_photo_info validates :biography, no_profanity: true # musicians has_many :band_musicians, :class_name => "JamRuby::BandMusician" has_many :users, :through => :band_musicians, :class_name => "JamRuby::User" # genres has_and_belongs_to_many :genres, :class_name => "JamRuby::Genre", :join_table => "bands_genres" # recordings has_many :recordings, :class_name => "JamRuby::Recording", :foreign_key => "band_id" # likers has_many :likers, :class_name => "JamRuby::BandLiker", :foreign_key => "band_id", :inverse_of => :band has_many :inverse_likers, :through => :likers, :class_name => "JamRuby::User", :foreign_key => "liker_id" # followers has_many :band_followers, :class_name => "JamRuby::BandFollower", :foreign_key => "band_id" has_many :followers, :through => :band_followers, :class_name => "JamRuby::User" has_many :inverse_band_followers, :through => :followers, :class_name => "JamRuby::BandFollower", :foreign_key => "follower_id" has_many :inverse_followers, :through => :inverse_band_followers, :source => :band, :class_name => "JamRuby::Band" # invitations has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id" # music_sessions has_many :music_sessions, :class_name => "JamRuby::MusicSession", :foreign_key => "band_id" has_many :music_session_history, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "band_id", :inverse_of => :band def liker_count return self.likers.size end def follower_count return self.followers.size end def recording_count return self.recordings.size end def session_count return self.music_sessions.size end def location loc = self.city.blank? ? '' : self.city loc = loc.blank? ? self.state : "#{loc}, #{self.state}" unless self.state.blank? #loc = loc.blank? ? self.country : "#{loc}, #{self.country}" unless self.country.blank? loc end def validate_photo_info if updating_photo # we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io) errors.add(:original_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.original_fpfile_photo.nil? || self.original_fpfile_photo["key"].nil? || self.original_fpfile_photo["url"].nil? errors.add(:cropped_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.cropped_fpfile_photo.nil? || self.cropped_fpfile_photo["key"].nil? || self.cropped_fpfile_photo["url"].nil? end end def add_member(user_id, admin) BandMusician.create(:band_id => self.id, :user_id => user_id, :admin => admin) end def self.musician_index(band_id) @musicians = User.joins(:band_musicians).where(:bands_musicians => {:band_id => "#{band_id}"}) end def self.pending_musicians(band_id) @musicians = User.joins(:received_band_invitations) .where(:band_invitations => {:band_id => "#{band_id}"}) .where(:band_invitations => {:accepted => nil}) end def self.recording_index(current_user, band_id) hide_private = false band = Band.find(band_id) # hide private Recordings from anyone who's not in the Band unless band.users.exists? current_user hide_private = true end if hide_private recordings = Recording.joins(:band_recordings) .where(:bands_recordings => {:band_id => "#{band_id}"}, :public => true) else recordings = Recording.joins(:band_recordings) .where(:bands_recordings => {:band_id => "#{band_id}"}) end return recordings end def self.search(query, options = { :limit => 10 }) # only issue search if at least 2 characters are specified if query.nil? || query.length < 2 return [] end # create 'anded' statement query = Search.create_tsquery(query) if query.nil? || query.length == 0 return [] end return Band.where("name_tsv @@ to_tsquery('jamenglish', ?)", query).limit(options[:limit]) end # helper method for creating / updating a Band def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url) user = User.find(user_id) # new band if id.nil? # ensure person creating this Band is a Musician unless user.musician? raise JamRuby::PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR end validate_genres(genres, false) band = Band.new() # band update else validate_genres(genres, true) band = Band.find(id) # ensure user updating Band details is a Band member unless band.users.exists? user raise PermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR end end # name band.name = name unless name.nil? # website band.website = website unless website.nil? # biography band.biography = biography unless biography.nil? # city band.city = city unless city.nil? # state band.state = state unless state.nil? # country band.country = country unless country.nil? # genres unless genres.nil? ActiveRecord::Base.transaction do # delete all genres for this band first unless band.id.nil? || band.id.length == 0 band.genres.delete_all end # loop through each genre in the array and save to the db genres.each do |genre_id| g = Genre.find(genre_id) band.genres << g end end end # photo url band.photo_url = photo_url unless photo_url.nil? # logo url band.logo_url = logo_url unless logo_url.nil? band.updated_at = Time.now.getutc band.save # add the creator as the admin if id.nil? BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) end return band end def update_photo(original_fpfile, cropped_fpfile, crop_selection, aws_bucket) self.updating_photo = true cropped_s3_path = cropped_fpfile["key"] return self.update_attributes( :original_fpfile_photo => original_fpfile, :cropped_fpfile_photo => cropped_fpfile, :cropped_s3_path_photo => cropped_s3_path, :crop_selection_photo => crop_selection, :photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false) ) end def delete_photo(aws_bucket) Band.transaction do unless self.cropped_s3_path.nil? S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path) + '/cropped.jpg') S3Util.delete(aws_bucket, self.cropped_s3_path) end return self.update_attributes( :original_fpfile_photo => nil, :cropped_fpfile_photo => nil, :cropped_s3_path_photo => nil, :crop_selection_photo => nil, :photo_url => nil ) end end private def self.validate_genres(genres, is_nil_ok) if is_nil_ok && genres.nil? return end if genres.nil? raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET else if genres.size < Limits::MIN_GENRES_PER_BAND raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET end if genres.size > Limits::MAX_GENRES_PER_BAND raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED end end end def stringify_photo_info # fpfile comes in as a hash, which is a easy-to-use and validate form. However, we store it as a VARCHAR, # so we need t oconvert it to JSON before storing it (otherwise it gets serialized as a ruby object) # later, when serving this data out to the REST API, we currently just leave it as a string and make a JSON capable # client parse it, because it's very rare when it's needed at all self.original_fpfile_photo = original_fpfile_photo.to_json if !original_fpfile_photo.nil? self.cropped_fpfile_photo = cropped_fpfile_photo.to_json if !cropped_fpfile_photo.nil? self.crop_selection_photo = crop_selection_photo.to_json if !crop_selection_photo.nil? end end end