2015-07-27 15:02:37 +00:00
module JamRuby
class Teacher < ActiveRecord :: Base
include HtmlSanitize
html_sanitize strict : [ :biography , :website ]
2015-07-28 19:00:14 +00:00
attr_accessor :validate_introduction , :validate_basics , :validate_pricing
2015-08-28 20:11:52 +00:00
attr_accessible :genres , :teacher_experiences , :experiences_teaching , :experiences_education , :experiences_award
2016-06-01 00:20:03 +00:00
has_many :genres , :class_name = > " JamRuby::Genre " , :through = > :teachers_genres # , :order => "description"
has_many :teachers_genres , :class_name = > " JamRuby::TeacherGenre "
has_many :instruments , :class_name = > " JamRuby::Instrument " , through : :teachers_instruments # , :order => "description"
has_many :teachers_instruments , class_name : " JamRuby::TeacherInstrument "
has_many :subjects , :class_name = > " JamRuby::Subject " , :through = > :teachers_subjects # , :order => "description"
has_many :teachers_subjects , class_name : " JamRuby::TeacherSubject "
has_many :languages , :class_name = > " JamRuby::Language " , :through = > :teachers_languages # , :order => "description"
has_many :teachers_languages , class_name : " JamRuby::TeacherLanguage "
2015-07-27 15:02:37 +00:00
has_many :teacher_experiences , :class_name = > " JamRuby::TeacherExperience "
2016-08-03 01:46:15 +00:00
has_many :experiences_teaching , - > { where ( experience_type : 'teaching' ) } , :class_name = > " JamRuby::TeacherExperience "
has_many :experiences_education , - > { where ( experience_type : 'education' ) } , :class_name = > " JamRuby::TeacherExperience "
has_many :experiences_award , - > { where ( experience_type : 'award' ) } , :class_name = > " JamRuby::TeacherExperience "
2016-01-14 18:45:55 +00:00
has_many :reviews , :class_name = > " JamRuby::Review " , as : :target
2016-04-06 02:23:15 +00:00
has_many :lesson_sessions , :class_name = > " JamRuby::LessonSession "
has_many :lesson_package_purchases , :class_name = > " JamRuby::LessonPackagePurchase "
2016-08-03 01:46:15 +00:00
has_one :review_summary , :class_name = > " JamRuby::ReviewSummary " , as : :target
has_one :user , :class_name = > 'JamRuby::User' , foreign_key : :teacher_id
2016-04-06 02:23:15 +00:00
belongs_to :school , :class_name = > " JamRuby::School " , inverse_of : :teachers
2016-08-31 09:19:16 +00:00
belongs_to :retailer , :class_name = > " JamRuby::Retailer " , inverse_of : :teachers
2015-07-27 15:02:37 +00:00
validates :user , :presence = > true
2015-07-28 19:00:14 +00:00
validates :biography , length : { minimum : 5 , maximum : 4096 } , :if = > :validate_introduction
2016-08-03 01:46:15 +00:00
validates :introductory_video , :format = > { :with = > / (?:https?: \/ \/ )?(?:www \ .)?youtu(?: \ .be|be \ .com) \/ (?:watch \ ?v=)?([ \ w-]{10,}) / , message : " is not a valid youtube URL " } , :allow_blank = > true , :if = > :validate_introduction
2015-07-28 19:00:14 +00:00
validates :years_teaching , :presence = > true , :if = > :validate_introduction
validates :years_playing , :presence = > true , :if = > :validate_introduction
2016-02-06 23:32:20 +00:00
validates :teaches_test_drive , inclusion : { in : [ true , false ] } , :if = > :validate_pricing
2016-03-21 20:39:15 +00:00
validates :top_rated , inclusion : { in : [ true , false ] }
2016-02-06 23:32:20 +00:00
validates :test_drives_per_week , numericality : { only_integer : true , minimum : 2 , maximum : 10 } , :if = > :validate_pricing
2016-03-21 20:39:15 +00:00
validates :instruments , :length = > { minimum : 1 , message : " At least one instrument or subject is required " } , if : :validate_basics , unless : - > ( teacher ) { teacher . subjects . length > 0 }
validates :subjects , :length = > { minimum : 1 , message : " At least one instrument or subject is required " } , if : :validate_basics , unless : - > ( teacher ) { teacher . instruments . length > 0 }
validates :genres , :length = > { minimum : 1 , message : " At least one genre is required " } , if : :validate_basics
validates :languages , :length = > { minimum : 1 , message : " At least one language is required " } , if : :validate_basics
2015-07-28 19:00:14 +00:00
validate :offer_pricing , :if = > :validate_pricing
validate :offer_duration , :if = > :validate_pricing
2016-01-07 11:12:11 +00:00
validate :teaches_ages , :if = > :validate_basics
2015-07-27 15:02:37 +00:00
2016-06-01 00:20:03 +00:00
#default_scope { includes(:genres).order('created_at desc') }
2015-08-08 20:01:38 +00:00
2016-03-25 17:08:23 +00:00
after_save :update_profile_pct
def update_profile_pct
result = pct_complete
self . profile_pct = result [ :pct ]
self . profile_pct_summary = result . to_json
Teacher . where ( id : id ) . update_all ( profile_pct : self . profile_pct , profile_pct_summary : self . profile_pct_summary )
end
2017-03-22 12:39:06 +00:00
def is_guitar_center?
return school && school . is_guitar_center?
end
2016-01-28 19:55:17 +00:00
def self . index ( user , params = { } )
limit = params [ :per_page ]
limit || = 20
limit = limit . to_i
2016-06-01 00:20:03 +00:00
query = User . unscoped . joins ( :teacher )
2016-01-28 19:55:17 +00:00
2016-05-01 03:12:25 +00:00
# only show teachers with ready for session set to true
2016-04-06 02:23:15 +00:00
query = query . where ( 'teachers.ready_for_session_at IS NOT NULL' )
2017-03-22 12:39:06 +00:00
# always force GuitarCenter users to see only their school's teachers, regardless of what they picked
if user && ( user . is_guitar_center_student? || ( params [ :onlyMySchool ] && params [ :onlyMySchool ] != 'false' && user . school_id ) )
2016-05-16 16:39:20 +00:00
query = query . where ( " teachers.school_id = ? " , user . school_id )
end
2016-01-28 19:55:17 +00:00
instruments = params [ :instruments ]
if instruments && ! instruments . blank? && instruments . length > 0
query = query . joins ( " inner JOIN teachers_instruments AS tinst ON tinst.teacher_id = teachers.id " )
2016-03-21 20:39:15 +00:00
. where ( " tinst.instrument_id IN (?) " , instruments )
2015-07-27 15:02:37 +00:00
end
2016-01-28 19:55:17 +00:00
subjects = params [ :subjects ]
if subjects && ! subjects . blank? && subjects . length > 0
query = query . joins ( " inner JOIN teachers_subjects AS tsubjs ON tsubjs.teacher_id = teachers.id " )
. where ( 'tsubjs.subject_id IN (?)' , subjects )
end
2015-07-27 15:02:37 +00:00
2016-01-28 19:55:17 +00:00
genres = params [ :genres ]
if genres && ! genres . blank? && genres . length > 0
query = query . joins ( " inner JOIN teachers_genres AS tgenres ON tgenres.teacher_id = teachers.id " )
. where ( 'tgenres.genre_id IN (?)' , genres )
end
country = params [ :country ]
if country && country . length > 0
query = query . where ( country : country )
end
region = params [ :region ]
if region && region . length > 0
query = query . where ( state : region )
end
languages = params [ :languages ]
if languages && ! languages . blank? && languages . length > 0
2016-03-21 20:39:15 +00:00
query = query . joins ( " inner JOIN teachers_languages AS tlang ON tlang.teacher_id = teachers.id " )
. where ( 'tlang.language_id IN (?)' , languages )
2016-01-28 19:55:17 +00:00
end
years_teaching = params [ :years_teaching ] . to_i
2016-04-06 02:23:15 +00:00
if params [ :years_teaching ] && years_teaching > 0
2016-01-28 19:55:17 +00:00
query = query . where ( 'years_teaching >= ?' , years_teaching )
end
teaches_beginner = params [ :teaches_beginner ]
teaches_intermediate = params [ :teaches_intermediate ]
teaches_advanced = params [ :teaches_advanced ]
2016-04-06 02:23:15 +00:00
if teaches_beginner . present? || teaches_intermediate . present? || teaches_advanced . present?
2016-01-28 19:55:17 +00:00
clause = ''
2016-04-06 02:23:15 +00:00
if teaches_beginner == true
2016-01-28 19:55:17 +00:00
clause << 'teaches_beginner = true'
2016-01-07 11:12:11 +00:00
end
2016-04-06 02:23:15 +00:00
if teaches_intermediate == true
2016-01-28 19:55:17 +00:00
if clause . length > 0
clause << ' OR '
end
clause << 'teaches_intermediate = true'
2016-01-07 11:12:11 +00:00
end
2016-04-06 02:23:15 +00:00
if teaches_advanced == true
2016-01-28 19:55:17 +00:00
if clause . length > 0
clause << ' OR '
end
clause << 'teaches_advanced = true'
2016-01-07 11:12:11 +00:00
end
2016-01-28 19:55:17 +00:00
query = query . where ( clause )
end
2015-07-27 22:00:39 +00:00
2016-01-28 19:55:17 +00:00
student_age = params [ :student_age ] . to_i
2016-04-06 02:23:15 +00:00
if params [ :student_age ] && student_age > 0
2016-01-28 19:55:17 +00:00
query = query . where ( " teaches_age_lower <= ? AND (CASE WHEN teaches_age_upper = 0 THEN true ELSE teaches_age_upper >= ? END) " , student_age , student_age )
2015-07-27 15:02:37 +00:00
end
2016-01-28 19:55:17 +00:00
2017-07-10 02:21:29 +00:00
# don't show phantom teachers that teach 'bass guitar', 'acoustic guitar', 'electric guitar'
2017-06-26 19:59:13 +00:00
query = query . where ( " ((select count(checkgt.instrument_id) from teachers_instruments checkgt where checkgt.teacher_id = teachers.id AND checkgt.instrument_id IN ('bass guitar', 'acoustic guitar', 'electric guitar') ) = 0 AND phantom = true) OR phantom = false " )
2016-05-18 02:35:09 +00:00
# order in this way: https://jamkazam.atlassian.net/browse/VRFS-4058
# Real teachers who are marked as top.
# Real teachers who are not marked as top.
# Phantom teachers.
query = query . order ( " top_rated DESC, phantom ASC " )
2016-01-28 19:55:17 +00:00
current_page = params [ :page ] . nil? ? 1 : params [ :page ] . to_i
next_page = current_page + 1
# will_paginate gem
query = query . paginate ( :page = > current_page , :per_page = > limit )
2016-03-21 20:39:15 +00:00
if query . length == 0 # no more results
{ query : query , next_page : nil }
elsif query . length < limit # no more results
{ query : query , next_page : nil }
2016-01-28 19:55:17 +00:00
else
2016-03-21 20:39:15 +00:00
{ query : query , next_page : next_page }
2016-01-28 19:55:17 +00:00
end
end
def self . save_teacher ( user , params )
2016-08-03 01:46:15 +00:00
teacher = nil
Teacher . transaction do
teacher = build_teacher ( user , params )
if teacher . save
# flag the user as a teacher
teacher . user . is_a_teacher = true
teacher . user . save ( validate : false )
end
if teacher . errors . any?
raise ActiveRecord :: Rollback
end
2016-04-21 14:23:29 +00:00
end
2016-01-28 19:55:17 +00:00
teacher
2016-08-03 01:46:15 +00:00
2016-01-28 19:55:17 +00:00
end
def self . build_teacher ( user , params )
# ensure person creating this Teacher is a Musician
unless user && user . musician?
raise JamPermissionError , " must be a musician "
end
teacher = user . teacher
2016-04-06 02:23:15 +00:00
teacher || = Teacher . new
2016-01-28 19:55:17 +00:00
teacher . user = user
teacher . website = params [ :website ] if params . key? ( :website )
teacher . biography = params [ :biography ] if params . key? ( :biography )
2016-03-21 20:39:15 +00:00
teacher . introductory_video = params [ :introductory_video ] if params . key? ( :introductory_video )
teacher . years_teaching = params [ :years_teaching ] if params . key? ( :years_teaching )
teacher . years_playing = params [ :years_playing ] if params . key? ( :years_playing )
teacher . teaches_age_lower = params [ :teaches_age_lower ] if params . key? ( :teaches_age_lower )
teacher . teaches_age_upper = params [ :teaches_age_upper ] if params . key? ( :teaches_age_upper )
teacher . teaches_beginner = params [ :teaches_beginner ] if params . key? ( :teaches_beginner )
teacher . teaches_intermediate = params [ :teaches_intermediate ] if params . key? ( :teaches_intermediate )
teacher . teaches_advanced = params [ :teaches_advanced ] if params . key? ( :teaches_advanced )
teacher . prices_per_lesson = params [ :prices_per_lesson ] if params . key? ( :prices_per_lesson )
teacher . prices_per_month = params [ :prices_per_month ] if params . key? ( :prices_per_month )
teacher . lesson_duration_30 = params [ :lesson_duration_30 ] if params . key? ( :lesson_duration_30 )
teacher . lesson_duration_45 = params [ :lesson_duration_45 ] if params . key? ( :lesson_duration_45 )
teacher . lesson_duration_60 = params [ :lesson_duration_60 ] if params . key? ( :lesson_duration_60 )
teacher . lesson_duration_90 = params [ :lesson_duration_90 ] if params . key? ( :lesson_duration_90 )
teacher . lesson_duration_120 = params [ :lesson_duration_120 ] if params . key? ( :lesson_duration_120 )
teacher . price_per_lesson_30_cents = params [ :price_per_lesson_30_cents ] if params . key? ( :price_per_lesson_30_cents )
teacher . price_per_lesson_45_cents = params [ :price_per_lesson_45_cents ] if params . key? ( :price_per_lesson_45_cents )
teacher . price_per_lesson_60_cents = params [ :price_per_lesson_60_cents ] if params . key? ( :price_per_lesson_60_cents )
teacher . price_per_lesson_90_cents = params [ :price_per_lesson_90_cents ] if params . key? ( :price_per_lesson_90_cents )
teacher . price_per_lesson_120_cents = params [ :price_per_lesson_120_cents ] if params . key? ( :price_per_lesson_120_cents )
teacher . price_per_month_30_cents = params [ :price_per_month_30_cents ] if params . key? ( :price_per_month_30_cents )
teacher . price_per_month_45_cents = params [ :price_per_month_45_cents ] if params . key? ( :price_per_month_45_cents )
teacher . price_per_month_60_cents = params [ :price_per_month_60_cents ] if params . key? ( :price_per_month_60_cents )
teacher . price_per_month_90_cents = params [ :price_per_month_90_cents ] if params . key? ( :price_per_month_90_cents )
teacher . price_per_month_120_cents = params [ :price_per_month_120_cents ] if params . key? ( :price_per_month_120_cents )
2016-02-06 23:32:20 +00:00
teacher . teaches_test_drive = params [ :teaches_test_drive ] if params . key? ( :teaches_test_drive )
teacher . test_drives_per_week = params [ :test_drives_per_week ] if params . key? ( :test_drives_per_week )
2016-05-26 21:25:51 +00:00
teacher . test_drives_per_week = 10 if ! params . key? ( :test_drives_per_week ) # default to 10 in absence of others
2016-09-27 02:56:12 +00:00
if params . key? ( :school_id )
teacher . school_id = params [ :school_id ]
if ! teacher . joined_school_at
teacher . joined_school_at = Time . now
end
end
if params . key? ( :retailer_id )
teacher . retailer_id = params [ :retailer_id ]
if ! teacher . joined_retailer_at
teacher . joined_retailer_at = Time . now
end
end
2016-01-28 19:55:17 +00:00
2016-08-03 01:46:15 +00:00
# How to validate:
teacher . validate_introduction = ! ! params [ :validate_introduction ]
teacher . validate_pricing = ! ! params [ :validate_pricing ]
2016-04-21 14:23:29 +00:00
2016-01-28 19:55:17 +00:00
2016-08-03 01:46:15 +00:00
initial_save = teacher . save
2016-01-28 19:55:17 +00:00
teacher . validate_basics = ! ! params [ :validate_basics ]
2016-08-03 01:46:15 +00:00
if initial_save
# Many-to-many relations:
if params . key? ( :genres )
genres = params [ :genres ]
genres = [ ] if genres . nil?
teacher . genres . clear
genres . each do | genre_id |
teacher . genres << Genre . find ( genre_id )
end
end
if params . key? ( :instruments )
instruments = params [ :instruments ]
instruments = [ ] if instruments . nil?
teacher . instruments . clear
instruments . each do | instrument_id |
teacher . instruments << Instrument . find ( instrument_id )
end
end
if params . key? ( :subjects )
subjects = params [ :subjects ]
subjects = [ ] if subjects . nil?
teacher . subjects . clear
subjects . each do | subject_id |
teacher . subjects << Subject . find ( subject_id )
end
end
if params . key? ( :languages )
languages = params [ :languages ]
languages = [ ] if languages . nil?
teacher . languages . clear
languages . each do | language_id |
teacher . languages << Language . find ( language_id )
end
end
# Experience:
[ :teaching , :education , :award ] . each do | experience_type |
key = " experiences_ #{ experience_type } " . to_sym
if params . key? ( key )
list = params [ key ]
list = [ ] if list . nil?
experiences = list . collect do | exp |
TeacherExperience . new (
name : exp [ :name ] ,
experience_type : experience_type ,
organization : exp [ :organization ] ,
start_year : exp [ :start_year ] ,
end_year : exp [ :end_year ]
)
end # collect
# we blindly destroy/recreate on every resubmit
previous = teacher . send ( " #{ key . to_s } " )
previous . destroy_all
# Dynamically call the appropriate method (just setting the
# value doesn't result in the behavior we need)
teacher . send ( " #{ key . to_s } = " , experiences )
end # if
end # do
end
2016-01-28 19:55:17 +00:00
2016-07-17 15:16:27 +00:00
return teacher
2015-07-27 15:02:37 +00:00
end
2015-07-28 19:00:14 +00:00
2016-04-06 02:23:15 +00:00
def booking_price ( lesson_length , single )
price = nil
if single
price = self [ " price_per_lesson_ #{ lesson_length } _cents " ]
else
price = self [ " price_per_month_ #{ lesson_length } _cents " ]
end
if ! price . nil?
price / 100 . 0
else
price
end
end
2015-07-28 19:00:14 +00:00
def offer_pricing
unless prices_per_lesson . present? || prices_per_month . present?
errors . add ( :offer_pricing , " Must choose to price per lesson or per month " )
end
end
def offer_duration
unless lesson_duration_30 . present? || lesson_duration_45 . present? || lesson_duration_60 . present? || lesson_duration_90 . present? || lesson_duration_120 . present?
errors . add ( :offer_duration , " Must offer at least one duration " )
end
end
2016-01-07 11:12:11 +00:00
def teaches_ages
if teaches_age_lower > 0 && teaches_age_upper > 0 && ( teaches_age_upper < teaches_age_lower )
errors . add ( :ages_taught , " Age range is backwards " )
end
end
2016-01-14 18:45:55 +00:00
def recent_reviews
reviews . order ( 'created_at desc' ) . limit ( 20 )
end
2016-03-21 20:39:15 +00:00
2017-07-10 02:21:29 +00:00
def mark_background_checked ( time )
self . background_check_at = time
2016-03-21 20:39:15 +00:00
self . save!
end
def mark_session_ready
2016-03-21 21:37:13 +00:00
self . ready_for_session_at = Time . now
2016-03-21 20:39:15 +00:00
self . save!
end
def mark_top_rated
self . top_rated = true
self . save!
end
def mark_not_top_rated
self . top_rated = false
self . save!
end
2016-08-03 01:46:15 +00:00
2016-03-21 20:39:15 +00:00
def has_experiences_teaching?
experiences_teaching . count > 0
end
def has_experiences_education?
experiences_education . count > 0
end
def has_experiences_award?
experiences_award . count > 0
end
def has_stripe_billing?
2016-04-21 14:23:29 +00:00
user . has_stripe_connect?
2016-03-21 20:39:15 +00:00
end
def has_instruments_or_subject?
instruments . count > 0 || subjects . count > 0
end
def has_genres?
genres . count > 0
end
def has_languages?
languages . count > 0
end
def teaches_ages_specified?
( ! teaches_age_lower . nil? && teaches_age_lower > 0 ) || ( ! teaches_age_upper . nil? && teaches_age_upper > 0 )
end
def teaching_level_specified?
teaches_beginner || teaches_intermediate || teaches_advanced
end
def has_pricing_specified?
specified = false
durations_allowed = [ ]
[ 30 , 45 , 60 , 90 , 120 ] . each do | i |
durations_allowed << i if self [ " lesson_duration_ #{ i } " ]
end
durations_allowed . each do | i |
if self [ " price_per_lesson_ #{ i } _cents " ] || self [ " price_per_month_ #{ i } _cents " ]
specified = true
break
end
end
specified
end
def has_name_specified?
! user . anonymous?
end
2016-05-24 15:14:53 +00:00
def stripe_account_id
user . stripe_auth . uid if user . has_stripe_connect?
end
## !!!! this is only valid for tests
def stripe_account_id = ( new_acct_id )
2016-09-08 10:59:58 +00:00
user . stripe_account_id = new_acct_id
2016-05-24 15:14:53 +00:00
end
2016-03-21 20:39:15 +00:00
# how complete is their profile?
def pct_complete
@part_complete || = {
name_specified : has_name_specified? ,
experiences_teaching : has_experiences_teaching? ,
experiences_education : has_experiences_education? ,
experiences_award : has_experiences_award? ,
has_stripe_account : has_stripe_billing? ,
has_teacher_bio : ! biography . nil? ,
intro_video : ! introductory_video . nil? ,
years_teaching : years_teaching > 0 ,
years_playing : years_playing > 0 ,
instruments_or_subject : has_instruments_or_subject? ,
genres : genres . count > 0 ,
languages : languages . count > 0 ,
teaches_ages_specified : teaches_ages_specified? ,
teaching_level_specified : teaching_level_specified? ,
has_pricing_specified : has_pricing_specified?
}
done = 0
@part_complete . each do | k , v |
if v
done += 1
end
end
2016-03-21 21:37:13 +00:00
complete = 100 . 0 * done . to_f / @part_complete . length . to_f
2016-03-21 20:39:15 +00:00
@part_complete [ :pct ] = complete . round
@part_complete
end
2016-10-07 13:28:17 +00:00
def teaches
if instruments . length == 0
return ''
elsif instruments . length == 2
return 'Teaches ' + instruments [ 0 ] . description + ' and ' + instruments [ 1 ] . description
else
return 'Teaches ' + instruments . map { | i | i . description } . join ( ', ' )
end
end
2015-07-27 15:02:37 +00:00
end
end