303 lines
11 KiB
Ruby
303 lines
11 KiB
Ruby
module JamRuby
|
|
class Band < ActiveRecord::Base
|
|
include HtmlSanitize
|
|
html_sanitize strict: [:biography, :website, :name]
|
|
|
|
attr_accessible :name, :website, :biography, :city, :state,
|
|
:country, :original_fpfile_photo, :cropped_fpfile_photo, :cropped_large_fpfile_photo,
|
|
:cropped_s3_path_photo, :cropped_large_s3_path_photo, :crop_selection_photo, :photo_url, :large_photo_url
|
|
|
|
attr_accessor :updating_photo, :skip_location_validation
|
|
|
|
self.primary_key = 'id'
|
|
|
|
before_save :stringify_photo_info , :if => :updating_photo
|
|
validates :biography, no_profanity: true, presence:true, length: {maximum: 4000}
|
|
validates :name, presence: true, no_profanity: true
|
|
validates :country, presence: true, :unless => :skip_location_validation
|
|
validates :state, presence: true, :unless => :skip_location_validation
|
|
validates :city, presence: true, :unless => :skip_location_validation
|
|
|
|
validate :validate_photo_info
|
|
validate :require_at_least_one_genre
|
|
validate :limit_max_genres
|
|
|
|
before_save :check_lat_lng
|
|
before_save :check_website_url
|
|
|
|
# musicians
|
|
has_many :band_musicians, :class_name => "JamRuby::BandMusician"
|
|
has_many :users, :through => :band_musicians, :class_name => "JamRuby::User"
|
|
|
|
# genres
|
|
has_many :band_genres, class_name: "JamRuby::BandGenre"
|
|
has_many :genres, class_name: "JamRuby::Genre", :through => :band_genres
|
|
|
|
# recordings
|
|
has_many :recordings, :class_name => "JamRuby::Recording", :foreign_key => "band_id"
|
|
|
|
# self.id = likable_id in likes table
|
|
has_many :likers, :as => :likable, :class_name => "JamRuby::Like", :dependent => :destroy
|
|
|
|
# self.id = followable_id in follows table
|
|
has_many :followers, :as => :followable, :class_name => "JamRuby::Follow", :dependent => :destroy
|
|
|
|
# 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, :inverse_of => :band
|
|
|
|
# events
|
|
has_many :event_sessions, :class_name => "JamRuby::EventSession"
|
|
|
|
include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable)
|
|
acts_as_mappable
|
|
|
|
def liker_count
|
|
self.likers.size
|
|
end
|
|
|
|
def follower_count
|
|
self.followers.size
|
|
end
|
|
|
|
def recording_count
|
|
self.recordings.size
|
|
end
|
|
|
|
def session_count
|
|
self.music_sessions.size
|
|
end
|
|
|
|
def recent_history
|
|
recordings = Recording.where(:band_id => self.id)
|
|
.order('created_at DESC')
|
|
.limit(10)
|
|
|
|
msh = MusicSession.where(:band_id => self.id)
|
|
.order('created_at DESC')
|
|
.limit(10)
|
|
|
|
recordings.concat(msh)
|
|
recordings.sort! {|a,b| b.created_at <=> a.created_at}.first(5)
|
|
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?
|
|
errors.add(:cropped_large_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.cropped_large_fpfile_photo.nil? || self.cropped_large_fpfile_photo["key"].nil? || self.cropped_large_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.build_band(user, params)
|
|
|
|
id = params[:id]
|
|
|
|
# ensure person creating this Band is a Musician
|
|
unless user.musician?
|
|
raise PermissionError, "must be a musician"
|
|
end
|
|
|
|
band = id.blank? ? Band.new : Band.find(id)
|
|
|
|
# ensure user updating Band details is a Band member
|
|
unless band.new_record? || band.users.exists?(user)
|
|
raise PermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR
|
|
end
|
|
|
|
band.name = params[:name] if params.has_key?(:name)
|
|
band.website = params[:website] if params.has_key?(:website)
|
|
band.biography = params[:biography] if params.has_key?(:biography)
|
|
band.city = params[:city] if params.has_key?(:city)
|
|
band.state = params[:state] if params.has_key?(:state)
|
|
band.country = params[:country] if params.has_key?(:country)
|
|
band.photo_url = params[:photo_url] if params.has_key?(:photo_url)
|
|
band.logo_url = params[:logo_url] if params.has_key?(:logo_url)
|
|
|
|
if params.has_key?(:genres) && params[:genres]
|
|
# loop through each genre in the array and save to the db
|
|
genres = []
|
|
params[:genres].each { |genre_id| genres << Genre.find(genre_id) }
|
|
band.genres = genres
|
|
end
|
|
|
|
|
|
band
|
|
end
|
|
|
|
# helper method for creating / updating a Band
|
|
def self.save(user, params)
|
|
band = build_band(user, params)
|
|
|
|
if band.save
|
|
# add the creator as the admin
|
|
BandMusician.create(:band_id => band.id, :user_id => user.id, :admin => true) if params[:id].blank?
|
|
end
|
|
|
|
band
|
|
end
|
|
|
|
def escape_filename(path)
|
|
dir = File.dirname(path)
|
|
file = File.basename(path)
|
|
"#{dir}/#{ERB::Util.url_encode(file)}"
|
|
end
|
|
|
|
def update_photo(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, aws_bucket)
|
|
self.updating_photo = true
|
|
|
|
cropped_s3_path = cropped_fpfile["key"]
|
|
cropped_large_s3_path = cropped_large_fpfile["key"]
|
|
|
|
self.update_attributes(
|
|
:original_fpfile_photo => original_fpfile,
|
|
:cropped_fpfile_photo => cropped_fpfile,
|
|
:cropped_large_fpfile_photo => cropped_large_fpfile,
|
|
:cropped_s3_path_photo => cropped_s3_path,
|
|
:cropped_large_s3_path_photo => cropped_large_s3_path,
|
|
:crop_selection_photo => crop_selection,
|
|
:photo_url => S3Util.url(aws_bucket, escape_filename(cropped_s3_path), :secure => false),
|
|
:large_photo_url => S3Util.url(aws_bucket, escape_filename(cropped_large_s3_path), :secure => false))
|
|
end
|
|
|
|
def delete_photo(aws_bucket)
|
|
|
|
Band.transaction do
|
|
|
|
unless self.cropped_s3_path_photo.nil?
|
|
S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path_photo) + '/cropped.jpg')
|
|
S3Util.delete(aws_bucket, self.cropped_s3_path_photo)
|
|
S3Util.delete(aws_bucket, self.cropped_large_s3_path_photo)
|
|
end
|
|
|
|
return self.update_attributes(
|
|
:original_fpfile_photo => nil,
|
|
:cropped_fpfile_photo => nil,
|
|
:cropped_large_fpfile_photo => nil,
|
|
:cropped_s3_path_photo => nil,
|
|
:cropped_large_s3_path_photo => nil,
|
|
:crop_selection_photo => nil,
|
|
:photo_url => nil,
|
|
:large_photo_url => nil)
|
|
end
|
|
end
|
|
|
|
def check_lat_lng
|
|
if (city_changed? || state_changed? || country_changed?)
|
|
update_lat_lng
|
|
end
|
|
true
|
|
end
|
|
|
|
def update_lat_lng
|
|
if self.city
|
|
query = { :city => self.city }
|
|
query[:region] = self.state unless self.state.blank?
|
|
query[:countrycode] = self.country unless self.country.blank?
|
|
if geo = GeoIpLocations.where(query).limit(1).first
|
|
geo.latitude = nil if geo.latitude = 0
|
|
geo.longitude = nil if geo.longitude = 0
|
|
if geo.latitude && geo.longitude && (self.lat != geo.latitude || self.lng != geo.longitude)
|
|
self.lat, self.lng = geo.latitude, geo.longitude
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
self.lat, self.lng = nil, nil
|
|
false
|
|
end
|
|
|
|
def check_website_url
|
|
if website_changed? && self.website.present?
|
|
self.website.strip!
|
|
self.website = "http://#{self.website}" unless self.website =~ /^http/
|
|
end
|
|
true
|
|
end
|
|
|
|
def to_s
|
|
name
|
|
end
|
|
|
|
def in_real_session?(session)
|
|
b_members = self.users.sort_by(&:id).map(&:id)
|
|
s_members = session.users.sort_by(&:id).map(&:id)
|
|
(b_members - s_members).blank?
|
|
end
|
|
|
|
def self.after_maxmind_import(use_copied = true)
|
|
table_suffix = use_copied ? '_copied' : ''
|
|
Band.connection.execute("UPDATE bands SET lat = geo.latitude, lng = geo.longitude FROM geoiplocations#{table_suffix} as geo WHERE bands.city = geo.city AND bands.state = geo.region AND bands.country = geo.countrycode")
|
|
end
|
|
|
|
private
|
|
|
|
def require_at_least_one_genre
|
|
if self.genres.size < Limits::MIN_GENRES_PER_BAND
|
|
errors.add(:genres, ValidationMessages::BAND_GENRE_MINIMUM_NOT_MET)
|
|
end
|
|
end
|
|
|
|
def limit_max_genres
|
|
if self.genres.size > Limits::MAX_GENRES_PER_BAND
|
|
errors.add(:genres, ValidationMessages::BAND_GENRE_LIMIT_EXCEEDED)
|
|
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
|