2016-01-04 19:42:11 +00:00
require 'kickbox'
2013-03-15 04:22:31 +00:00
include Devise :: Models
2012-08-06 03:01:00 +00:00
module JamRuby
class User < ActiveRecord :: Base
2014-08-19 01:41:44 +00:00
include Geokit :: ActsAsMappable :: Glue unless defined? ( acts_as_mappable )
include HtmlSanitize
html_sanitize strict : [ :first_name , :last_name , :city , :state , :country , :biography ]
2013-03-15 04:22:31 +00:00
#devise: for later: :trackable
2014-07-22 19:36:45 +00:00
@@log = Logging . logger [ User ]
2014-08-28 03:36:57 +00:00
VALID_EMAIL_REGEX = / \ A[ \ w+ \ -.]+@([a-z \ d \ -]+ \ .)+[a-z]+ \ z /i
2014-07-20 02:11:16 +00:00
JAM_REASON_REGISTRATION = 'r'
JAM_REASON_NETWORK_TEST = 'n'
2014-07-22 19:36:45 +00:00
JAM_REASON_FTUE = 'g'
2014-07-20 02:11:16 +00:00
JAM_REASON_JOIN = 'j'
JAM_REASON_IMPORT = 'i'
2014-07-22 19:36:45 +00:00
JAM_REASON_LOGIN = 'l'
2014-04-01 23:38:36 +00:00
2014-11-15 02:47:56 +00:00
# MOD KEYS
MOD_GEAR = " gear "
MOD_GEAR_FRAME_OPTIONS = " show_frame_options "
MOD_NO_SHOW = " no_show "
2015-08-30 10:00:00 +00:00
HOWTO_USE_VIDEO_NOSHOW = 'how-to-use-video'
CONFIGURE_VIDEO_NOSHOW = 'configure-video'
2014-11-15 02:47:56 +00:00
2015-01-16 23:20:07 +00:00
# MIN/MAX AUDIO LATENCY
MINIMUM_AUDIO_LATENCY = 2
MAXIMUM_AUDIO_LATENCY = 10000
2018-01-23 03:50:45 +00:00
ONBOARDING_STATUS_UNASSIGNED = " Unassigned "
ONBOARDING_STATUS_ASSIGNED = " Assigned "
ONBOARDING_STATUS_EMAILED = " Emailed "
ONBOARDING_STATUS_ONBOARDED = " Onboarded "
ONBOARDING_STATUS_LOST = " Lost "
ONBOARDING_STATUS_ESCALATED = " Escalated "
2018-02-25 22:28:12 +00:00
ONBOARDING_STATUS_FREE_LESSON = " One Free Lesson Taken "
2018-01-23 03:50:45 +00:00
ONBOARDING_STATUS_PAID_LESSON = " Paid Lesson Taken "
ONBOARDING_STATUES = [ ONBOARDING_STATUS_UNASSIGNED , ONBOARDING_STATUS_ASSIGNED , ONBOARDING_STATUS_EMAILED , ONBOARDING_STATUS_ONBOARDED , ONBOARDING_STATUS_LOST , ONBOARDING_STATUS_ESCALATED , ONBOARDING_STATUS_FREE_LESSON , ONBOARDING_STATUS_PAID_LESSON ]
SESSION_OUTCOME_SUCCESSFUL = " Successful "
SESSION_OUTCOME_SETUP_WIZARD_FAILURE = " Setup Wizard Failure "
SESSION_OUTCOME_NO_AUDIO_STREAM = " No Audio Stream in Session "
SESSION_OUTCOME_NO_VIDEO_STREAM = " No Video Stream In Session "
SESSION_OUTCOME_OTHER = " Other "
SESSION_OUTCOMES = [ SESSION_OUTCOME_SUCCESSFUL , SESSION_OUTCOME_SETUP_WIZARD_FAILURE , SESSION_OUTCOME_NO_AUDIO_STREAM , SESSION_OUTCOME_NO_VIDEO_STREAM , SESSION_OUTCOME_OTHER ]
LOST_REASON_LOST_INTEREST = " Lost Interest "
LOST_REASON_NO_COMPUTER = " No Win/Mac Computer "
LOST_REASON_NO_BROADBAND = " No Broadband Internet "
LOST_REASON_NO_WEBCAM = " No Webcam "
LOST_REASON_BAD_INTERNET = " Bad Internet "
LOST_REASON_SETUP_WIZARD_FAILURE = " Setup Wizard Failure "
LOST_REASON_NO_AUDIO_STREAM = " No Audio Stream In Session "
LOST_REASON_NO_VIDEO_STREAM = " No Video Stream In Session "
LOST_REASON_OTHER = " Other "
LOST_REASONS = [ LOST_REASON_LOST_INTEREST , LOST_REASON_NO_COMPUTER , LOST_REASON_NO_BROADBAND , LOST_REASON_NO_WEBCAM , LOST_REASON_BAD_INTERNET , LOST_REASON_SETUP_WIZARD_FAILURE , LOST_REASON_NO_AUDIO_STREAM , LOST_REASON_NO_VIDEO_STREAM , LOST_REASON_OTHER ]
ESCALATION_REASON_NO_AUDIO_STREAM = " No Audio Stream In Session "
ESCALATION_REASON_NO_VIDEO_STREAM = " No Video Stream In Session "
ESCALATION_REASON_SETUP_WIZARD_FAILURE = " Setup Wizard Failure "
ESCALATION_REASON_OTHER = " Other "
ESCALATION_REASONS = [ ESCALATION_REASON_NO_AUDIO_STREAM , ESCALATION_REASON_NO_VIDEO_STREAM , ESCALATION_REASON_SETUP_WIZARD_FAILURE , ESCALATION_REASON_OTHER ]
2014-04-01 23:38:36 +00:00
devise :database_authenticatable , :recoverable , :rememberable
2012-08-18 18:48:43 +00:00
2013-10-28 17:03:58 +00:00
acts_as_mappable
2013-03-15 04:22:31 +00:00
2016-03-25 17:08:23 +00:00
after_save :update_teacher_pct
2013-10-28 14:22:06 +00:00
2014-05-17 19:55:26 +00:00
attr_accessible :first_name , :last_name , :email , :city , :password , :password_confirmation , :state , :country , :birth_date , :subscribe_email , :terms_of_service , :original_fpfile , :cropped_fpfile , :cropped_large_fpfile , :cropped_s3_path , :cropped_large_s3_path , :photo_url , :large_photo_url , :crop_selection
2013-05-14 19:02:22 +00:00
# updating_password corresponds to a lost_password
2017-07-10 02:21:29 +00:00
attr_accessor :test_drive_packaging , :validate_instruments , :updating_password , :updating_email , :updated_email , :update_email_confirmation_url , :administratively_created , :current_password , :setting_password , :confirm_current_password , :updating_avatar , :updating_progression_field , :mods_json , :expecting_gift_card , :purchase_required
2014-01-21 14:51:03 +00:00
belongs_to :icecast_server_group , class_name : " JamRuby::IcecastServerGroup " , inverse_of : :users , foreign_key : 'icecast_server_group_id'
2016-01-04 19:42:11 +00:00
has_many :controlled_sessions , :class_name = > " JamRuby::MusicSession " , inverse_of : :session_controller , foreign_key : :session_controller_id
2015-12-08 02:25:43 +00:00
2012-11-13 07:40:06 +00:00
# authorizations (for facebook, etc -- omniauth)
2012-11-13 21:21:04 +00:00
has_many :user_authorizations , :class_name = > " JamRuby::UserAuthorization "
2012-11-13 02:52:05 +00:00
2015-07-20 16:01:08 +00:00
has_many :reviews , :class_name = > " JamRuby::Review "
2016-06-01 00:20:03 +00:00
has_one :review_summary , :class_name = > " JamRuby::ReviewSummary " , as : :target
2015-07-20 16:01:08 +00:00
2015-07-06 20:34:27 +00:00
# calendars (for scheduling NOT in music_session)
has_many :calendars , :class_name = > " JamRuby::Calendar "
2012-10-29 10:45:47 +00:00
# connections (websocket-gateway)
2012-10-02 05:02:02 +00:00
has_many :connections , :class_name = > " JamRuby::Connection "
2012-10-01 21:27:32 +00:00
2012-10-29 10:45:47 +00:00
# friend requests
2014-03-25 15:29:08 +00:00
has_many :sent_friend_requests , :class_name = > " JamRuby::FriendRequest " , :foreign_key = > 'user_id'
has_many :received_friend_requests , :class_name = > " JamRuby::FriendRequest " , :foreign_key = > 'friend_id'
2012-10-14 02:18:20 +00:00
2012-10-29 10:45:47 +00:00
# instruments
2016-01-04 19:42:11 +00:00
has_many :musician_instruments , :class_name = > " JamRuby::MusicianInstrument " , :foreign_key = > 'player_id'
2012-10-30 05:42:16 +00:00
has_many :instruments , :through = > :musician_instruments , :class_name = > " JamRuby::Instrument "
2012-11-07 13:10:41 +00:00
2012-10-29 10:45:47 +00:00
# bands
2012-11-21 19:48:39 +00:00
has_many :band_musicians , :class_name = > " JamRuby::BandMusician "
2012-10-30 05:42:16 +00:00
has_many :bands , :through = > :band_musicians , :class_name = > " JamRuby::Band "
2018-01-15 03:50:26 +00:00
belongs_to :teacher , :class_name = > " JamRuby::Teacher " , foreign_key : :teacher_id , inverse_of : :user
2016-05-05 02:20:38 +00:00
2014-12-05 07:50:03 +00:00
# genres
has_many :genre_players , as : :player , class_name : " JamRuby::GenrePlayer " , dependent : :destroy
has_many :genres , through : :genre_players , class_name : " JamRuby::Genre "
2012-11-16 02:08:37 +00:00
# recordings
2014-02-15 23:23:00 +00:00
has_many :owned_recordings , :class_name = > " JamRuby::Recording " , :foreign_key = > " owner_id "
2013-04-25 06:50:52 +00:00
has_many :recordings , :through = > :claimed_recordings , :class_name = > " JamRuby::Recording "
has_many :claimed_recordings , :class_name = > " JamRuby::ClaimedRecording " , :inverse_of = > :user
2014-05-06 13:34:38 +00:00
has_many :playing_claimed_recordings , :class_name = > " JamRuby::ActiveMusicSession " , :inverse_of = > :claimed_recording_initiator
2015-01-07 23:44:56 +00:00
has_many :playing_jam_tracks , :class_name = > " JamRuby::ActiveMusicSession " , :inverse_of = > :jam_track_initiator
2012-11-16 02:08:37 +00:00
2017-07-10 02:21:29 +00:00
# VRFS-2916 jam_tracks.id is varchar: REMOVE
2015-03-25 16:11:10 +00:00
# has_many :jam_tracks_played, :class_name => "JamRuby::PlayablePlay", :foreign_key => 'player_id', :conditions => "jam_track_id IS NOT NULL"
2015-03-23 20:06:32 +00:00
# VRFS-2916 jam_tracks.id is varchar: ADD
2016-07-17 15:16:27 +00:00
has_many :jam_tracks_played , - > { where ( " playable_type = 'JamRuby::JamTrack' " ) } , :class_name = > " JamRuby::PlayablePlay " , :foreign_key = > 'player_id'
2015-03-23 20:06:32 +00:00
2014-02-15 23:23:00 +00:00
# self.id = user_id in likes table
has_many :likings , :class_name = > " JamRuby::Like " , :inverse_of = > :user , :dependent = > :destroy
# self.id = likable_id in likes table
2014-02-16 01:24:51 +00:00
has_many :likers , :as = > :likable , :class_name = > " JamRuby::Like " , :dependent = > :destroy
2014-02-15 23:23:00 +00:00
# self.id = user_id in follows table
has_many :followings , :class_name = > " JamRuby::Follow " , :inverse_of = > :user , :dependent = > :destroy
# self.id = followable_id in follows table
2014-02-16 01:24:51 +00:00
has_many :followers , :as = > :followable , :class_name = > " JamRuby::Follow " , :dependent = > :destroy
2012-12-17 06:01:48 +00:00
2015-01-12 06:20:19 +00:00
# text messages
2016-04-27 03:22:49 +00:00
has_many :text_messages , :class_name = > " JamRuby::TextMessage " , :foreign_key = > " target_user_id "
2015-01-12 06:20:19 +00:00
2013-03-31 18:07:46 +00:00
# notifications
has_many :notifications , :class_name = > " JamRuby::Notification " , :foreign_key = > " target_user_id "
2018-02-15 04:16:32 +00:00
2014-05-02 16:30:56 +00:00
# chats
has_many :chats , :class_name = > " JamRuby::ChatMessage " , :foreign_key = > " user_id "
2012-10-29 10:45:47 +00:00
# friends
2012-10-26 10:33:39 +00:00
has_many :friendships , :class_name = > " JamRuby::Friendship " , :foreign_key = > " user_id "
has_many :friends , :through = > :friendships , :class_name = > " JamRuby::User "
2012-10-01 21:27:32 +00:00
has_many :inverse_friendships , :class_name = > " JamRuby::Friendship " , :foreign_key = > " friend_id "
2012-10-26 10:33:39 +00:00
has_many :inverse_friends , :through = > :inverse_friendships , :source = > :user , :class_name = > " JamRuby::User "
2012-11-03 19:32:27 +00:00
# connections / music sessions
2014-05-06 13:34:38 +00:00
has_many :created_music_sessions , :foreign_key = > " user_id " , :inverse_of = > :user , :class_name = > " JamRuby::ActiveMusicSession " # sessions *created* by the user
has_many :music_sessions , :through = > :connections , :class_name = > " JamRuby::ActiveMusicSession "
2012-10-26 10:33:39 +00:00
2012-11-04 03:02:11 +00:00
# invitations
2012-10-26 10:33:39 +00:00
has_many :received_invitations , :foreign_key = > " receiver_id " , :inverse_of = > :receiver , :class_name = > " JamRuby::Invitation "
has_many :sent_invitations , :foreign_key = > " sender_id " , :inverse_of = > :sender , :class_name = > " JamRuby::Invitation "
2012-11-07 13:10:41 +00:00
2012-11-25 19:37:54 +00:00
# fan invitations
2012-11-16 02:50:03 +00:00
has_many :received_fan_invitations , :foreign_key = > " receiver_id " , :inverse_of = > :receiver , :class_name = > " JamRuby::FanInvitation "
has_many :sent_fan_invitations , :foreign_key = > " sender_id " , :inverse_of = > :sender , :class_name = > " JamRuby::FanInvitation "
2012-11-24 18:22:44 +00:00
# band invitations
has_many :received_band_invitations , :inverse_of = > :receiver , :foreign_key = > " user_id " , :class_name = > " JamRuby::BandInvitation "
has_many :sent_band_invitations , :inverse_of = > :sender , :foreign_key = > " creator_id " , :class_name = > " JamRuby::BandInvitation "
2013-01-06 20:46:48 +00:00
# session history
2014-05-06 13:34:38 +00:00
has_many :music_session_histories , :foreign_key = > " user_id " , :class_name = > " JamRuby::MusicSession " , :inverse_of = > :user
2013-07-30 17:26:26 +00:00
has_many :music_session_user_histories , :foreign_key = > " user_id " , :class_name = > " JamRuby::MusicSessionUserHistory " , :inverse_of = > :user
2013-01-06 20:46:48 +00:00
2013-01-15 02:13:45 +00:00
# saved tracks
2013-01-22 19:15:52 +00:00
has_many :recorded_tracks , :foreign_key = > " user_id " , :class_name = > " JamRuby::RecordedTrack " , :inverse_of = > :user
2014-10-03 19:12:09 +00:00
has_many :recorded_videos , :foreign_key = > " user_id " , :class_name = > " JamRuby::RecordedVideo " , :inverse_of = > :user
2015-01-31 21:20:48 +00:00
has_many :recorded_backing_tracks , :foreign_key = > " user_id " , :class_name = > " JamRuby::RecordedBackingTrack " , :inverse_of = > :user
2014-10-23 04:10:49 +00:00
has_many :quick_mixes , :foreign_key = > " user_id " , :class_name = > " JamRuby::QuickMix " , :inverse_of = > :user
2015-02-25 16:43:21 +00:00
has_many :recorded_jam_track_tracks , :foreign_key = > " user_id " , :class_name = > " JamRuby::RecordedJamTrackTrack " , :inverse_of = > :user
# jam track recordings started
has_many :initiated_jam_track_recordings , :foreign_key = > 'jam_track_initiator_id' , :class_name = > " JamRuby::Recording " , :inverse_of = > :jam_track_initiator
2013-01-15 02:13:45 +00:00
2013-03-15 04:22:31 +00:00
# invited users
has_many :invited_users , :foreign_key = > " sender_id " , :class_name = > " JamRuby::InvitedUser "
2013-08-09 02:12:43 +00:00
# crash dumps
has_many :crash_dumps , :foreign_key = > " user_id " , :class_name = > " JamRuby::CrashDump "
2014-03-10 06:31:20 +00:00
# events
has_many :event_sessions , :class_name = > " JamRuby::EventSession "
2015-11-13 13:12:58 +00:00
# gift cards
2016-01-04 19:42:11 +00:00
has_many :gift_cards , :class_name = > " JamRuby::GiftCard "
has_many :gift_card_purchases , :class_name = > " JamRuby::GiftCardPurchase "
2015-11-29 19:58:10 +00:00
2015-11-13 13:12:58 +00:00
2014-04-20 22:54:49 +00:00
# affiliate_partner
2015-06-03 19:22:21 +00:00
has_one :affiliate_partner , :class_name = > " JamRuby::AffiliatePartner " , :foreign_key = > :partner_user_id , inverse_of : :partner_user
2014-04-20 22:54:49 +00:00
belongs_to :affiliate_referral , :class_name = > " JamRuby::AffiliatePartner " , :foreign_key = > :affiliate_referral_id , :counter_cache = > :referral_user_count
2014-04-30 03:01:28 +00:00
# diagnostics
has_many :diagnostics , :class_name = > " JamRuby::Diagnostic "
2014-04-20 22:54:49 +00:00
2016-01-04 19:42:11 +00:00
# jam_tracks
2014-11-04 20:55:12 +00:00
has_many :jam_track_rights , :class_name = > " JamRuby::JamTrackRight " , :foreign_key = > " user_id "
2016-07-17 15:16:27 +00:00
has_many :purchased_jam_tracks , - > { order ( :created_at ) } , :through = > :jam_track_rights , :class_name = > " JamRuby::JamTrack " , :source = > :jam_track
2014-11-04 20:55:12 +00:00
2016-04-06 02:23:15 +00:00
# lessons
has_many :lesson_purchases , :class_name = > " JamRuby::LessonPackagePurchase " , :foreign_key = > " user_id " , inverse_of : :user
has_many :student_lesson_bookings , :class_name = > " JamRuby::LessonBooking " , :foreign_key = > " user_id " , inverse_of : :user
has_many :teacher_lesson_bookings , :class_name = > " JamRuby::LessonBooking " , :foreign_key = > " teacher_id " , inverse_of : :teacher
has_many :teacher_distributions , :class_name = > " JamRuby::TeacherDistribution " , :foreign_key = > " teacher_id " , inverse_of : :teacher
has_many :teacher_payments , :class_name = > " JamRuby::TeacherPayment " , :foreign_key = > " teacher_id " , inverse_of : :teacher
2016-06-03 04:32:09 +00:00
has_many :test_drive_package_choice_teachers , :class_name = > " JamRuby::TestDrivePackageChoiceTeacher " , :foreign_key = > " teacher_id "
has_many :test_drive_package_choices , :class_name = > " JamRuby::TestDrivePackageChoice " , :foreign_key = > " user_id " , inverse_of : :user
2016-05-05 02:20:38 +00:00
belongs_to :desired_package , :class_name = > " JamRuby::LessonPackageType " , :foreign_key = > " lesson_package_type_id " , inverse_of : :user_desired_packages # used to hold whether user last wanted test drive 4/2/1
2017-07-10 02:21:29 +00:00
belongs_to :lesson_package_needs_purchase , :class_name = > " JamRuby::LessonPackageType " , :foreign_key = > " lesson_package_needs_purchase_id " , inverse_of : :users_needing_purchase
2014-11-04 20:55:12 +00:00
# Shopping carts
has_many :shopping_carts , :class_name = > " JamRuby::ShoppingCart "
2014-07-26 19:18:17 +00:00
# score history
has_many :from_score_histories , :class_name = > " JamRuby::ScoreHistory " , foreign_key : 'from_user_id'
has_many :to_score_histories , :class_name = > " JamRuby::ScoreHistory " , foreign_key : 'to_user_id'
2015-04-03 20:34:12 +00:00
has_many :sales , :class_name = > 'JamRuby::Sale' , dependent : :destroy
has_many :recurly_transaction_web_hooks , :class_name = > 'JamRuby::RecurlyTransactionWebHook' , dependent : :destroy
2012-11-09 06:51:17 +00:00
# This causes the authenticate method to be generated (among other stuff)
2013-03-15 04:22:31 +00:00
#has_secure_password
2012-08-06 03:01:00 +00:00
2016-01-04 19:42:11 +00:00
has_many :online_presences , :class_name = > " JamRuby::OnlinePresence " , :foreign_key = > 'player_id'
has_many :performance_samples , :class_name = > " JamRuby::PerformanceSample " , :foreign_key = > 'player_id'
2015-01-31 21:07:34 +00:00
2015-02-23 06:21:36 +00:00
has_one :musician_search , :class_name = > 'JamRuby::MusicianSearch'
2015-05-18 04:00:12 +00:00
has_one :band_search , :class_name = > 'JamRuby::BandSearch'
2016-04-06 02:23:15 +00:00
belongs_to :teacher , :class_name = > 'JamRuby::Teacher' , foreign_key : :teacher_id
2015-02-23 06:21:36 +00:00
2016-01-04 03:38:30 +00:00
has_many :jam_track_session , :class_name = > " JamRuby::JamTrackSession "
2016-05-28 02:33:26 +00:00
has_many :taken_lessons , :class_name = > " JamRuby::LessonSession " , inverse_of : :user , foreign_key : :user_id
2016-04-06 02:23:15 +00:00
has_many :taught_lessons , :class_name = > " JamRuby::LessonSession " , inverse_of : :teacher , foreign_key : :teacher_id
belongs_to :school , :class_name = > " JamRuby::School " , inverse_of : :students
2018-01-23 03:50:45 +00:00
belongs_to :onboarder , :class_name = > " JamRuby::User " , inverse_of : :onboarding_users , foreign_key : :onboarder_id
has_many :onboarding_users , :class_name = > " JamRuby::User " , inverse_of : :onboarder , foreign_key : :onboarder_id
2016-04-06 02:23:15 +00:00
has_one :owned_school , :class_name = > " JamRuby::School " , inverse_of : :user
2016-08-31 09:19:16 +00:00
has_one :owned_retailer , :class_name = > " JamRuby::Retailer " , inverse_of : :user
2016-06-03 04:32:09 +00:00
has_many :test_drive_package_choices , :class_name = > " JamRuby::TestDrivePackageChoice "
2016-02-03 16:56:14 +00:00
has_many :jamblasters_users , class_name : " JamRuby::JamblasterUser "
has_many :jamblasters , class_name : 'JamRuby::Jamblaster' , through : :jamblasters_users
2016-08-03 01:46:15 +00:00
has_many :proposed_slots , class_name : 'JamRuby::LessonBookingSlot' , inverse_of : :proposer , dependent : :destroy , foreign_key : :proposer_id
has_many :charges , class_name : 'JamRuby::Charge' , dependent : :destroy
2016-08-31 09:19:16 +00:00
has_many :posa_cards , class_name : 'JamRuby::PosaCard' , dependent : :destroy
2016-02-03 16:56:14 +00:00
2015-10-16 19:01:18 +00:00
before_save :default_anonymous_names
2012-12-09 04:05:54 +00:00
before_save :create_remember_token , :if = > :should_validate_password?
2016-01-04 19:42:11 +00:00
before_save :stringify_avatar_info , :if = > :updating_avatar
2012-11-03 15:38:00 +00:00
2016-05-10 02:32:34 +00:00
after_save :after_save
2016-01-04 19:42:11 +00:00
validates :first_name , length : { maximum : 50 } , no_profanity : true
2015-10-16 19:01:18 +00:00
validates :last_name , length : { maximum : 50 } , no_profanity : true
2014-02-25 05:41:43 +00:00
validates :biography , length : { maximum : 4000 } , no_profanity : true
2014-04-01 23:38:36 +00:00
validates :email , presence : true , format : { with : VALID_EMAIL_REGEX }
2013-07-10 20:18:25 +00:00
validates :update_email , presence : true , format : { with : VALID_EMAIL_REGEX } , :if = > :updating_email
2013-06-22 02:28:42 +00:00
2013-05-14 19:02:22 +00:00
validates_length_of :password , minimum : 6 , maximum : 100 , :if = > :should_validate_password?
2012-10-07 04:57:23 +00:00
validates_presence_of :password_confirmation , :if = > :should_validate_password?
validates_confirmation_of :password , :if = > :should_validate_password?
2013-05-14 19:02:22 +00:00
2016-01-04 19:42:11 +00:00
validates :terms_of_service , :acceptance = > { :accept = > true , :on = > :create , :allow_nil = > false }
2015-03-16 18:27:39 +00:00
validates :reuse_card , :inclusion = > { :in = > [ true , false ] }
2016-04-06 02:23:15 +00:00
validates :is_a_student , :inclusion = > { :in = > [ true , false ] }
validates :is_a_teacher , :inclusion = > { :in = > [ true , false ] }
2015-03-20 13:48:00 +00:00
validates :has_redeemable_jamtrack , :inclusion = > { :in = > [ true , false ] }
2016-01-04 19:42:11 +00:00
validates :gifted_jamtracks , presence : true , :numericality = > { :less_than_or_equal_to = > 100 }
2013-03-15 04:22:31 +00:00
validates :subscribe_email , :inclusion = > { :in = > [ nil , true , false ] }
2013-06-22 02:28:42 +00:00
validates :musician , :inclusion = > { :in = > [ true , false ] }
2013-10-21 22:13:53 +00:00
validates :show_whats_next , :inclusion = > { :in = > [ nil , true , false ] }
2016-02-11 03:09:45 +00:00
validates :is_a_student , :inclusion = > { :in = > [ true , false ] }
validates :is_a_teacher , :inclusion = > { :in = > [ true , false ] }
2018-01-23 03:50:45 +00:00
validates :is_onboarder , :inclusion = > { :in = > [ true , false , nil ] }
2016-07-17 15:16:27 +00:00
#validates :mods, json: true
2016-01-04 19:42:11 +00:00
validates_numericality_of :last_jam_audio_latency , greater_than : MINIMUM_AUDIO_LATENCY , less_than : MAXIMUM_AUDIO_LATENCY , :allow_nil = > true
validates :last_jam_updated_reason , :inclusion = > { :in = > [ nil , JAM_REASON_REGISTRATION , JAM_REASON_NETWORK_TEST , JAM_REASON_FTUE , JAM_REASON_JOIN , JAM_REASON_IMPORT , JAM_REASON_LOGIN ] }
2013-06-22 02:28:42 +00:00
2015-07-15 15:04:45 +00:00
# stored in cents
2016-01-04 19:42:11 +00:00
validates_numericality_of :paid_sessions_hourly_rate , greater_than : 0 , less_than : 200000 , :if = > :paid_sessions
2015-07-15 15:04:45 +00:00
# stored in cents
2016-01-04 19:42:11 +00:00
validates_numericality_of :paid_sessions_daily_rate , greater_than : 0 , less_than : 5000000 , :if = > :paid_sessions
2015-07-15 15:04:45 +00:00
2013-07-10 20:18:25 +00:00
# custom validators
2016-02-08 12:56:54 +00:00
validate :validate_musician_instruments , if : :validate_instruments
2013-05-14 19:02:22 +00:00
validate :validate_current_password
validate :validate_update_email
2013-05-31 01:59:37 +00:00
validate :validate_avatar_info
2013-07-10 20:18:25 +00:00
validate :email_case_insensitive_uniqueness
validate :update_email_case_insensitive_uniqueness , :if = > :updating_email
2014-11-11 22:21:29 +00:00
validate :validate_mods
2015-11-13 13:12:58 +00:00
validate :presence_gift_card , :if = > :expecting_gift_card
2013-05-31 01:59:37 +00:00
2016-07-17 15:16:27 +00:00
scope :musicians , - > { where ( :musician = > true ) }
scope :fans , - > { where ( :musician = > false ) }
scope :geocoded_users , - > { where ( User . arel_table [ :last_jam_locidispid ] . not_eq ( nil ) ) }
scope :musicians_geocoded , - > { musicians . geocoded_users }
scope :email_opt_in , - > { where ( :subscribe_email = > true ) }
2018-05-21 02:57:53 +00:00
scope :came_through_amazon , - > { joins ( :posa_cards ) . where ( 'posa_cards.lesson_package_type_id in (?)' , LessonPackageType :: AMAZON_PACKAGES + LessonPackageType :: LESSON_PACKAGE_TYPES ) }
2013-11-23 07:44:13 +00:00
2016-05-10 02:32:34 +00:00
def after_save
if school_interest && ! school_interest_was
2016-09-08 23:06:04 +00:00
if education_interest
AdminMailer . partner ( { body : " #{ email } signed up via the https://www.jamkazam.com/landing/jamclass/education page. \n \n Full list is here: https://www.jamkazam.com/admin/admin/education_interests " , subject : " #{ email } is interested in education " } ) . deliver_now
else
AdminMailer . partner ( { body : " #{ email } signed up via the https://www.jamkazam.com/landing/jamclass/schools page. \n \n Full list is here: https://www.jamkazam.com/admin/admin/school_interests " , subject : " #{ email } is interested in schools " } ) . deliver_now
end
2016-05-10 02:32:34 +00:00
if owned_school . nil?
school = School . new
school . user = self
2016-09-09 14:06:02 +00:00
school . education = education_interest
2016-05-10 02:32:34 +00:00
school . save!
end
end
2016-10-07 13:28:17 +00:00
if retailer_interest && ! retailer_interest_was
2016-10-07 14:55:16 +00:00
AdminMailer . partner ( { body : " #{ email } signed up via the https://www.jamkazam.com/landing/jamclass/retailers page. \n \n Full list is here: https://www.jamkazam.com/admin/admin/retailer_interests " , subject : " #{ email } is interested in retailer program " } ) . deliver_now
2016-10-07 13:28:17 +00:00
if owned_retailer . nil?
retailer = Retailer . new
retailer . user = self
retailer . save!
end
end
2018-01-23 03:50:45 +00:00
if onboarding_lost_reason_changed? ||
onboarding_escalation_reason_changed? ||
onboarder_id_changed? ||
onboarding_email_5_sent_at_changed? ||
first_onboarding_free_lesson_at_changed? ||
first_onboarding_paid_lesson_at_changed? ||
2018-03-18 21:41:40 +00:00
second_onboarding_free_lesson_at_changed? ||
onboarding_onboarded_at_changed?
2018-02-25 22:28:12 +00:00
updates = { onboarding_status : self . computed_onboarding_status }
2018-03-10 00:27:27 +00:00
if onboarder_id_changed? && onboarder_id
2018-03-18 21:41:40 +00:00
begin
AdminMailer . ugly ( { to : onboarder . email , cc : APP_CONFIG . email_support_alias ,
2018-03-10 00:27:27 +00:00
subject : 'New student assigned to you' ,
2018-03-10 13:13:59 +00:00
body : " Hi #{ onboarder . first_name } , \n \n A new student has been assigned to you for onboarding. Please send the first introductory email to this student ASAP, and update the onboarding console to start tracking. \n \n New User Email: #{ email } \n \n Onboarding Management: https://www.jamkazam.com/client # /account/onboarder \n \n Thanks! \n \n Regards, \n Team JamKazam " } ) . deliver_now
2018-03-18 21:41:40 +00:00
rescue
puts " UNABLE TO INDICATE ONBOARDER ASSIGNED "
end
2018-03-10 00:27:27 +00:00
end
2018-03-18 21:41:40 +00:00
if onboarding_onboarded_at_changed? && onboarding_onboarded_at
begin
body = " A new student has been onboarded! \n \n User: #{ name } , #{ email } \n User Admin URL: #{ admin_url } \n \n "
if onboarder
body += " Onboarder: #{ onboarder . name } , #{ onboarder . email } \n Onboarder Admin URL: #{ onboarder . admin_url } \n \n "
end
body += " Onboarding Management: https://www.jamkazam.com/client # /account/onboarder \n \n "
AdminMailer . ugly ( { to : APP_CONFIG . email_support_alias ,
subject : " Student ' #{ name } ' successfully onboarded! " ,
body : body } ) . deliver_now
rescue
puts " UNABLE TO INDICATE ONBOARDED AT "
end
end
2018-02-25 22:28:12 +00:00
if first_onboarding_free_lesson_at_changed? || first_onboarding_paid_lesson_at_changed? || second_onboarding_free_lesson_at?
updates [ :stuck_take_flesson ] = false
updates [ :stuck_take_2nd_flesson ] = false
updates [ :stuck_take_plesson ] = false
end
2018-02-26 03:44:02 +00:00
if updates [ :onboarding_status ] == ONBOARDING_STATUS_ONBOARDED || updates [ :onboarding_status ] == ONBOARDING_STATUS_LOST || updates [ :onboarding_status ] == ONBOARDING_STATUS_ESCALATED
2018-03-03 21:39:55 +00:00
updates [ :send_onboarding_survey ] = true
2018-02-26 03:44:02 +00:00
end
2018-02-25 22:28:12 +00:00
User . where ( id : self . id ) . update_all ( updates )
2018-01-23 03:50:45 +00:00
end
2016-05-10 02:32:34 +00:00
end
2018-02-26 03:44:02 +00:00
def self . hourly_check
send_onboarding_surveys
2018-05-21 02:57:53 +00:00
send_take_lesson_poke
2018-05-26 17:19:59 +00:00
first_lesson_instructions
end
def self . first_lesson_instructions
User . came_through_amazon . joins ( taken_lessons : [ :music_session , :lesson_booking ] )
. where ( 'lesson_bookings.recurring = FALSE' )
. where ( 'lesson_sessions.status = ?' , LessonSession :: STATUS_APPROVED )
. where ( " scheduled_start - (INTERVAL '2 days') < ? " , Time . now )
. where ( 'sent_first_lesson_instr_email_at is null' )
. where ( 'second_onboarding_free_lesson_at is null' ) . each do | user |
UserMailer . amazon_first_lesson_instructions ( user ) . deliver_now
User . where ( id : user . id ) . update_all ( sent_first_lesson_instr_email_at : Time . now )
end
2018-02-26 03:44:02 +00:00
end
def self . send_onboarding_surveys
User . where ( send_onboarding_survey : true , sent_onboarding_survey_at : nil ) . each do | user |
UserMailer . onboarding_survey ( user ) . deliver_now
User . where ( id : user . id ) . update_all ( sent_onboarding_survey_at : Time . now )
end
end
2018-05-21 02:57:53 +00:00
def self . send_take_lesson_poke
User . came_through_amazon . where ( 'remind_take_lesson_times <= 2' ) . where ( 'first_lesson_booked_at is NULL' )
. where ( '(remind_take_lesson_at is NULL AND users.created_at < ?) OR remind_take_lesson_at < ? ' , 1 . hours . ago , 2 . days . ago ) . each do | user |
2018-05-27 14:46:06 +00:00
user . send_lesson_poke
2018-05-21 02:57:53 +00:00
end
end
2018-05-27 14:46:06 +00:00
def send_lesson_poke ( first = false )
if first && self . remind_take_lesson_times > 0
return
end
UserMailer . amazon_prompt_take_lesson ( self , Teacher . match_teacher ( self ) . user , self . remind_take_lesson_times ) . deliver_now
User . where ( id : self . id ) . update_all ( remind_take_lesson_at : Time . now , remind_take_lesson_times : self . remind_take_lesson_times + 1 )
end
2016-03-25 17:08:23 +00:00
def update_teacher_pct
if teacher
teacher . update_profile_pct
end
end
2016-05-05 02:20:38 +00:00
2018-02-25 22:28:12 +00:00
def is_waiting_onboarding
2018-05-21 02:57:53 +00:00
ONBOARDING_STATUS_UNASSIGNED == onboarding_status
2018-02-25 22:28:12 +00:00
end
def is_onboarding
2018-05-21 02:57:53 +00:00
ONBOARDING_STATUS_ASSIGNED == onboarding_status || ONBOARDING_STATUS_ESCALATED == onboarding_status || ONBOARDING_STATUS_EMAILED == onboarding_status
2018-02-25 22:28:12 +00:00
end
2013-09-30 02:37:22 +00:00
def user_progression_fields
2016-01-04 19:42:11 +00:00
@user_progression_fields || = Set . new [ " first_downloaded_client_at " , " first_ran_client_at " , " first_music_session_at " , " first_real_music_session_at " , " first_good_music_session_at " , " first_certified_gear_at " , " first_invited_at " , " first_friended_at " , " first_recording_at " , " first_social_promoted_at " , " first_played_jamtrack_at " ]
2013-09-30 02:37:22 +00:00
end
def update_progression_field ( field_name , time = DateTime . now )
@updating_progression_field = true
if self [ field_name ] . nil?
self [ field_name ] = time
self . save
end
end
2018-02-15 04:16:32 +00:00
def update_timezone ( timezone )
if timezone . nil?
return
end
2018-05-26 17:19:59 +00:00
2018-02-15 04:16:32 +00:00
begin
TZInfo :: Timezone . get ( timezone )
User . where ( id : self . id ) . update_all ( timezone : timezone )
rescue Exception = > e
@@log . error ( " unable to find timezone= #{ timezone } , e= #{ e } " )
end
end
2018-05-26 17:19:59 +00:00
def tz_safe
tz_identifier = 'America/Chicago'
if self . timezone
tz_identifier = self . timezone
end
TZInfo :: Timezone . get ( tz_identifier )
end
# formats at 6:30 am. input should be UTC
def local_hour_stmt ( datetime )
tz = tz_safe
tz . utc_to_local ( datetime ) . strftime ( " %l:%M %P " ) . strip
end
2015-11-13 13:12:58 +00:00
def has_any_free_jamtracks
has_redeemable_jamtrack || gifted_jamtracks > 0
end
def free_jamtracks
( has_redeemable_jamtrack ? 1 : 0 ) + gifted_jamtracks
end
def show_free_jamtrack?
ShoppingCart . user_has_redeemable_jam_track? ( self )
end
2013-09-30 02:37:22 +00:00
def failed_qualification ( reason )
self . last_failed_certified_gear_at = DateTime . now
self . last_failed_certified_gear_reason = reason
self . save
end
2013-03-15 04:22:31 +00:00
def validate_musician_instruments
errors . add ( :musician_instruments , ValidationMessages :: INSTRUMENT_MINIMUM_NOT_MET ) if ! administratively_created && musician && musician_instruments . length == 0
errors . add ( :musician_instruments , ValidationMessages :: INSTRUMENT_LIMIT_EXCEEDED ) if ! administratively_created && musician && musician_instruments . length > 5
end
2014-11-11 22:21:29 +00:00
# let's work to stop junk from getting into the mods array; this is essentially the schema
def validate_mods
mods_json . each do | key , value |
2014-11-15 02:47:56 +00:00
if key == MOD_NO_SHOW || key == MOD_GEAR
errors . add ( :mods , ValidationMessages :: MODS_MUST_BE_HASH ) unless value . is_a? ( Hash )
2014-11-11 22:21:29 +00:00
else
errors . add ( :mods , ValidationMessages :: MODS_UNKNOWN_KEY )
end
end
end
2015-11-13 13:12:58 +00:00
def presence_gift_card
if self . gift_cards . length == 0
errors . add ( :gift_card , ValidationMessages :: NOT_FOUND )
end
end
2013-05-14 19:02:22 +00:00
def validate_current_password
2013-05-10 12:10:33 +00:00
# checks if the user put in their current password (used when changing your email, for instance)
2013-05-14 19:02:22 +00:00
errors . add ( :current_password , ValidationMessages :: NOT_YOUR_PASSWORD ) if should_confirm_existing_password? && ! valid_password? ( self . current_password )
2013-05-10 12:10:33 +00:00
end
2013-05-14 19:02:22 +00:00
def validate_update_email
2013-05-13 03:27:12 +00:00
if updating_email && self . update_email == self . email
errors . add ( :update_email , ValidationMessages :: EMAIL_MATCHES_CURRENT )
2013-07-10 20:18:25 +00:00
elsif updating_email && User . where ( " email ILIKE ? " , self . update_email ) . first != nil
2013-05-13 03:27:12 +00:00
errors . add ( :update_email , ValidationMessages :: EMAIL_ALREADY_TAKEN )
end
2013-05-10 12:10:33 +00:00
end
2012-08-29 13:21:30 +00:00
2013-05-31 01:59:37 +00:00
def validate_avatar_info
if updating_avatar
# 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 , ValidationMessages :: INVALID_FPFILE ) if self . original_fpfile . nil? || self . original_fpfile [ " key " ] . nil? || self . original_fpfile [ " url " ] . nil?
errors . add ( :cropped_fpfile , ValidationMessages :: INVALID_FPFILE ) if self . cropped_fpfile . nil? || self . cropped_fpfile [ " key " ] . nil? || self . cropped_fpfile [ " url " ] . nil?
2014-02-06 16:31:52 +00:00
errors . add ( :cropped_large_fpfile , ValidationMessages :: INVALID_FPFILE ) if self . cropped_large_fpfile . nil? || self . cropped_large_fpfile [ " key " ] . nil? || self . cropped_large_fpfile [ " url " ] . nil?
2013-05-31 01:59:37 +00:00
end
end
2013-07-10 20:18:25 +00:00
def email_case_insensitive_uniqueness
# using the case insensitive unique check of active record will downcase the field, which is not what we want--we want to preserve original casing
search = User . where ( " email ILIKE ? " , self . email ) . first
if search != nil && search != self
errors . add ( :email , ValidationMessages :: EMAIL_ALREADY_TAKEN )
end
end
def update_email_case_insensitive_uniqueness
# using the case insensitive unique check of active record will downcase the field, which is not what we want--we want to preserve original casing
search = User . where ( " update_email ILIKE ? " , self . update_email ) . first
if search != nil && search != self
errors . add ( :update_email , ValidationMessages :: EMAIL_ALREADY_TAKEN )
end
end
2012-10-14 02:18:20 +00:00
def online
2014-12-07 22:04:10 +00:00
online?
2012-10-14 02:18:20 +00:00
end
2015-10-19 15:07:53 +00:00
def anonymous?
first_name == 'Anonymous' && last_name == 'Anonymous'
end
2012-11-18 02:59:59 +00:00
def name
2015-10-19 15:07:53 +00:00
if anonymous?
2015-10-16 19:01:18 +00:00
'Anonymous'
else
" #{ first_name } #{ last_name } "
end
2012-11-18 02:59:59 +00:00
end
2018-05-26 17:19:59 +00:00
def greetings
if anonymous?
" Hello - "
else
" Hello #{ first_name } - "
end
end
2016-03-21 20:39:15 +00:00
def location ( country = false )
2013-01-06 12:34:16 +00:00
loc = self . city . blank? ? '' : self . city
loc = loc . blank? ? self . state : " #{ loc } , #{ self . state } " unless self . state . blank?
2016-03-21 20:39:15 +00:00
if country
loc = loc . blank? ? self . country : " #{ loc } , #{ self . country } " unless self . country . blank?
end
2013-01-06 12:34:16 +00:00
loc
end
def location = location_hash
2014-05-13 04:13:16 +00:00
unless location_hash . nil?
2013-01-06 12:34:16 +00:00
self . city = location_hash [ :city ]
self . state = location_hash [ :state ]
self . country = location_hash [ :country ]
2014-05-13 04:13:16 +00:00
end
2012-11-07 13:10:41 +00:00
end
2013-03-15 04:22:31 +00:00
def musician?
return musician
end
2012-10-07 04:57:23 +00:00
def should_validate_password?
2013-03-15 04:22:31 +00:00
( updating_password || new_record? )
2013-03-01 13:35:50 +00:00
end
2013-05-10 12:10:33 +00:00
def should_confirm_existing_password?
2013-05-14 19:02:22 +00:00
confirm_current_password
2013-05-10 12:10:33 +00:00
end
2013-03-01 13:35:50 +00:00
def end_user_created?
return ! administratively_created
2012-10-07 04:57:23 +00:00
end
2012-08-26 18:28:08 +00:00
2014-02-16 13:40:03 +00:00
def pending_friend_request? ( user )
FriendRequest . where ( " ((user_id=' #{ self . id } ' AND friend_id=' #{ user . id } ') OR (user_id=' #{ user . id } ' AND friend_id=' #{ self . id } ')) AND status is null " ) . size > 0
end
2012-10-07 18:02:26 +00:00
def friends? ( user )
2016-07-17 15:16:27 +00:00
self . friends . exists? ( user . id )
2012-10-07 18:02:26 +00:00
end
2012-11-06 04:47:50 +00:00
def friend_count
2014-02-16 01:24:51 +00:00
self . friends . size
2012-11-06 04:47:50 +00:00
end
2014-02-16 01:24:51 +00:00
# check if "this user" likes entity
def likes? ( entity )
2014-02-16 07:28:35 +00:00
self . likings . where ( :likable_id = > entity . id ) . size > 0
2012-12-17 07:02:20 +00:00
end
2014-02-16 01:24:51 +00:00
def liking_count
self . likings . size
2013-12-18 23:48:55 +00:00
end
2014-02-16 01:24:51 +00:00
def liker_count
self . likers . size
2012-11-06 04:47:50 +00:00
end
2014-02-16 01:24:51 +00:00
# check if "this user" follows entity
def following? ( entity )
2014-02-16 07:28:35 +00:00
self . followings . where ( :followable_id = > entity . id ) . size > 0
2012-12-17 07:02:20 +00:00
end
2014-02-16 01:24:51 +00:00
def following_count
self . followings . size
2014-02-15 16:55:01 +00:00
end
2014-02-16 01:24:51 +00:00
def follower_count
self . followers . size
2012-11-06 04:47:50 +00:00
end
2012-12-04 03:39:57 +00:00
def recording_count
2014-02-16 01:24:51 +00:00
self . recordings . size
2012-12-04 03:39:57 +00:00
end
2015-01-29 05:45:47 +00:00
def age
now = Time . now . utc . to_date
2017-07-10 02:21:29 +00:00
self . birth_date . nil? ? nil : now . year - self . birth_date . year - ( self . birth_date . to_date . change ( :year = > now . year ) > now ? 1 : 0 )
2015-01-29 05:45:47 +00:00
end
2012-12-04 03:39:57 +00:00
def session_count
2014-11-07 18:05:07 +00:00
MusicSession . where ( " user_id = ? AND started_at IS NOT NULL " , self . id ) . size
2012-12-04 03:39:57 +00:00
end
2014-01-21 06:45:51 +00:00
2014-07-12 13:55:58 +00:00
# count up any session you are RSVP'ed to
def upcoming_session_count
2016-07-17 15:16:27 +00:00
MusicSession . scheduled_rsvp ( self , true ) . count
2014-07-12 13:55:58 +00:00
end
2015-03-17 18:52:30 +00:00
def purchased_jamtracks_count
self . purchased_jam_tracks . count
end
2015-04-12 18:45:26 +00:00
def sales_count
self . sales . count
end
2014-05-29 18:03:33 +00:00
def joined_score
2014-06-15 15:35:15 +00:00
return nil unless has_attribute? ( :score )
2014-05-31 23:07:25 +00:00
a = read_attribute ( :score )
a . nil? ? nil : a . to_i
2014-05-29 18:03:33 +00:00
end
2014-06-15 15:35:15 +00:00
def music_session_id
return nil unless has_attribute? ( :music_session_id )
read_attribute ( :music_session_id )
end
2014-10-20 01:18:05 +00:00
# ===== ARTIFICIAL ATTRIBUTES CREATED BY ActiveMusicSession.ams_users, MusicSession.sms_users
2014-08-18 15:37:55 +00:00
def full_score
return nil unless has_attribute? ( :full_score )
a = read_attribute ( :full_score )
2014-06-15 15:35:15 +00:00
a . nil? ? nil : a . to_i
end
2014-08-18 15:37:55 +00:00
def internet_score
return nil unless has_attribute? ( :internet_score )
a = read_attribute ( :internet_score )
a . nil? ? nil : a . to_i
end
def audio_latency
return nil unless has_attribute? ( :audio_latency )
a = read_attribute ( :audio_latency )
a . nil? ? nil : a . to_i
end
2016-01-04 19:42:11 +00:00
2014-08-18 15:37:55 +00:00
# ====== END ARTIFICAL ATTRIBUTES
2014-10-20 01:18:05 +00:00
def score_info ( destination_user )
if self . last_jam_locidispid && destination_user . last_jam_locidispid
2016-07-17 15:16:27 +00:00
ActiveRecord :: Base . connection . execute ( " select score from current_network_scores where alocidispid = #{ self . last_jam_locidispid } and blocidispid = #{ destination_user . last_jam_locidispid } " ) . check
2014-10-20 01:18:05 +00:00
else
nil
end
end
2014-04-30 03:01:28 +00:00
# mods comes back as text; so give ourselves a parsed version
def mods_json
2016-07-17 15:16:27 +00:00
@mods_json || = mods ? mods : { }
2014-11-11 22:21:29 +00:00
end
# new_modes should be a regular hash with non-symbolized keys (vs symbolized keys)
def mod_merge ( new_mods )
self . mods = ( mods_json . merge ( new_mods ) do | key , old_val , new_val |
2014-11-15 02:47:56 +00:00
if key == MOD_NO_SHOW || key == MOD_GEAR
# we take the values from previous hash, and merge it with the new hash
2014-11-11 22:21:29 +00:00
old_val . merge ( new_val )
else
raise " unknown in mode_merge key: #{ key } "
end
2016-07-17 15:16:27 +00:00
end )
2014-11-11 22:21:29 +00:00
@mods_json = nil # invalidate this since we've updated self.mods
2014-11-17 23:16:30 +00:00
2014-04-30 03:01:28 +00:00
end
2014-11-15 02:47:56 +00:00
# any mod with the value 'null' will be deleted
def delete_mod ( root_key , sub_key )
mod = mods_json
root = mod [ root_key ]
if root
root . delete ( sub_key )
# check if root key is completely empty
mod . delete ( root_key ) if root . length == 0
# check if mod key is empty
mod = nil if mod . length == 0
end
2016-07-17 15:16:27 +00:00
self . mods = mod . nil? ? nil : mod
2014-11-15 02:47:56 +00:00
@mods_json = nil # invalidate this since we've updated self.mods
end
def get_mod ( root_key , sub_key )
mod = mods_json
root = mod [ root_key ]
root [ sub_key ] if root
end
def get_gear_mod ( sub_key )
get_mod ( MOD_GEAR , sub_key )
end
def get_no_show_mod ( sub_key )
get_mod ( MOD_NO_SHOW , sub_key )
2014-04-30 03:01:28 +00:00
end
2014-04-30 20:29:10 +00:00
def heartbeat_interval_client
mods_json [ :heartbeat_interval_client ]
2014-04-30 03:01:28 +00:00
end
2014-04-30 20:29:10 +00:00
def connection_expire_time_client
mods_json [ :connection_expire_time_client ]
2014-04-30 03:01:28 +00:00
end
2014-12-08 02:35:30 +00:00
def recent_history ( session_id , claimed_recording_id )
2014-12-06 14:34:30 +00:00
# used to exclude currently viewed recording
2014-12-08 02:35:30 +00:00
recording_exclusion = " claimed_recordings.id != ' #{ claimed_recording_id } ' " if claimed_recording_id
2014-09-12 01:52:26 +00:00
recordings = Recording
2016-01-04 19:42:11 +00:00
. joins ( :claimed_recordings )
. where ( :owner_id = > self . id )
. where ( " claimed_recordings.user_id = ' #{ self . id } ' " )
. where ( 'claimed_recordings.is_public=true' )
. where ( recording_exclusion )
. order ( 'created_at DESC' )
. limit ( 10 )
2014-12-06 14:34:30 +00:00
# used to exclude currently viewed session
2016-01-04 19:42:11 +00:00
session_exclusion = " music_sessions.id != ' #{ session_id } ' " if session_id
2014-12-06 14:34:30 +00:00
msh = MusicSession
2016-01-04 19:42:11 +00:00
. where ( :user_id = > self . id )
. where ( :fan_access = > true )
. where ( session_exclusion )
. order ( 'created_at DESC' )
. limit ( 10 )
2014-01-26 21:46:41 +00:00
2016-07-17 15:16:27 +00:00
results = recordings . concat ( msh )
results = results . sort! { | a , b | b . created_at < = > a . created_at } . first ( 5 )
2014-01-21 06:45:51 +00:00
end
2014-03-26 17:09:48 +00:00
# returns the # of new notifications
def new_notifications
2014-03-27 18:43:15 +00:00
search = Notification . select ( 'id' ) . where ( target_user_id : self . id )
search = search . where ( 'created_at > ?' , self . notification_seen_at ) if self . notification_seen_at
search . count
end
# the user can pass in a timestamp string, or the keyword 'LATEST'
# if LATEST is specified, we'll use the latest_notification as the timestamp
# if not, just use seen as-is
def update_notification_seen_at seen
new_latest_seen = nil
if seen == 'LATEST'
latest = self . latest_notification
new_latest_seen = latest . created_at if latest
else
new_latest_seen = seen
end
self . notification_seen_at = new_latest_seen
end
def latest_notification
Notification . select ( 'created_at' ) . where ( target_user_id : id ) . limit ( 1 ) . order ( 'created_at DESC' ) . first
2014-03-26 17:09:48 +00:00
end
2012-12-04 03:39:57 +00:00
def confirm_email!
2012-12-09 04:05:54 +00:00
self . email_confirmed = true
2016-01-04 19:42:11 +00:00
self . email_needs_verification = false
2012-12-09 04:05:54 +00:00
end
def my_session_settings
unless self . session_settings . nil?
2016-07-17 15:16:27 +00:00
return self . session_settings
2012-12-09 04:05:54 +00:00
else
return " "
end
2012-12-04 03:39:57 +00:00
end
2013-01-06 20:46:48 +00:00
def session_history ( user_id , band_id = nil , genre = nil )
2014-05-06 13:34:38 +00:00
return MusicSession . index ( self , user_id , band_id , genre )
2013-01-06 20:46:48 +00:00
end
def session_user_history ( user_id , session_id )
return MusicSessionUserHistory . where ( " music_session_id=' #{ session_id } ' " )
end
2013-06-24 21:31:40 +00:00
# always returns a non-null value for photo-url,
# using the generic avatar if no user photo available
def resolved_photo_url
if self . photo_url == nil || self . photo_url == ''
2014-02-07 23:56:39 +00:00
" #{ APP_CONFIG . external_root_url } /assets/shared/avatar_generic.png "
2013-06-24 21:31:40 +00:00
else
return self . photo_url
end
end
2012-10-07 04:57:23 +00:00
def to_s
return email unless email . nil?
2012-11-15 03:24:30 +00:00
2015-10-16 19:01:18 +00:00
return name unless name . nil?
2012-11-15 03:24:30 +00:00
2014-04-30 03:01:28 +00:00
id
2012-08-29 13:21:30 +00:00
end
2017-07-10 02:21:29 +00:00
2012-12-14 03:32:23 +00:00
def set_password ( old_password , new_password , new_password_confirmation )
2013-05-14 19:02:22 +00:00
# so that UserObserver knows to send a confirmation email on success
self . setting_password = true
# so that should_validate_password? fires
self . updating_password = true
2016-01-04 19:42:11 +00:00
attributes = { :password = > new_password , :password_confirmation = > new_password_confirmation }
2013-05-14 19:02:22 +00:00
# taken liberally from Devise::DatabaseAuthenticatable.update_with_password
if valid_password? ( old_password )
2016-01-04 19:42:11 +00:00
update_attributes ( attributes )
2013-05-14 19:02:22 +00:00
else
self . assign_attributes ( attributes )
self . valid?
2013-05-14 22:33:02 +00:00
self . errors . add ( :current_password , old_password . blank? ? :blank : :invalid )
2013-05-14 19:02:22 +00:00
end
#clean_up_passwords
2012-12-22 00:56:16 +00:00
end
def self . set_password_from_token ( email , token , new_password , new_password_confirmation )
2013-07-10 20:18:25 +00:00
user = User . where ( " email ILIKE ? " , email ) . first
2013-07-05 08:24:12 +00:00
if user . nil? || user . reset_password_token != token || Time . now - user . reset_password_token_created > 3 . days || new_password . length < 6 || new_password != new_password_confirmation
2012-12-22 00:56:16 +00:00
raise JamRuby :: JamArgumentError
end
user . reset_password_token = nil
user . reset_password_token_created = nil
user . change_password ( new_password , new_password_confirmation )
user . save
end
2016-01-04 19:42:11 +00:00
2012-12-22 00:56:16 +00:00
def change_password ( new_password , new_password_confirmation )
2017-07-10 02:21:29 +00:00
# FIXME: Should verify that the new password meets certain quality criteria. Really, maybe that should be a
2012-12-14 03:32:23 +00:00
# verification step.
2016-01-04 19:42:11 +00:00
self . updating_password = true
2012-12-14 03:32:23 +00:00
self . password = new_password
self . password_confirmation = new_password_confirmation
2016-07-17 15:16:27 +00:00
UserMailer . password_changed ( self ) . deliver_now
2012-12-13 17:15:47 +00:00
end
2013-07-05 08:24:12 +00:00
def self . reset_password ( email , base_uri )
2013-07-10 20:18:25 +00:00
user = User . where ( " email ILIKE ? " , email ) . first
2014-04-01 23:38:36 +00:00
raise JamRuby :: JamArgumentError . new ( 'unknown email' , :email ) if user . nil?
2012-12-22 00:56:16 +00:00
user . reset_password_token = SecureRandom . urlsafe_base64
user . reset_password_token_created = Time . now
user . save
2013-07-05 08:24:12 +00:00
reset_url = " #{ base_uri } /reset_password_token?token= #{ user . reset_password_token } &email= #{ CGI . escape ( email ) } "
2016-07-17 15:16:27 +00:00
UserMailer . password_reset ( user , reset_url ) . deliver_now
2012-12-28 07:30:03 +00:00
user
2012-12-22 00:56:16 +00:00
end
2012-12-17 07:02:20 +00:00
def self . band_index ( user_id )
bands = Band . joins ( :band_musicians )
. where ( :bands_musicians = > { :user_id = > " #{ user_id } " } )
return bands
end
def self . recording_index ( current_user , user_id )
hide_private = false
# hide private recordings from anyone but the current user
if current_user . id != user_id
hide_private = true
end
if hide_private
recordings = Recording . joins ( :musician_recordings )
2016-01-04 19:42:11 +00:00
. where ( :musicians_recordings = > { :user_id = > " #{ user_id } " } , :public = > true )
2012-12-17 07:02:20 +00:00
else
recordings = Recording . joins ( :musician_recordings )
2016-01-04 19:42:11 +00:00
. where ( :musicians_recordings = > { :user_id = > " #{ user_id } " } )
2012-12-17 07:02:20 +00:00
end
return recordings
end
2012-12-13 17:15:47 +00:00
2015-02-15 02:02:26 +00:00
def update_genres ( gids , genre_type )
2014-12-05 07:50:03 +00:00
unless self . new_record?
2016-01-04 19:42:11 +00:00
GenrePlayer . delete_all ( [ " player_id = ? AND player_type = ? AND genre_type = ? " ,
2015-02-15 02:02:26 +00:00
self . id , self . class . name , genre_type ] )
2014-12-05 07:50:03 +00:00
end
2015-02-15 02:02:26 +00:00
2014-12-05 07:50:03 +00:00
gids . each do | gid |
2015-02-15 02:02:26 +00:00
genre_player = GenrePlayer . new
genre_player . player_id = self . id
genre_player . player_type = self . class . name
genre_player . genre_id = gid
2016-01-04 19:42:11 +00:00
genre_player . genre_type = genre_type
2015-02-15 02:02:26 +00:00
self . genre_players << genre_player
2014-12-05 07:50:03 +00:00
end
end
2015-02-15 02:02:26 +00:00
def update_online_presences ( online_presences )
2015-02-15 13:23:26 +00:00
unless self . new_record?
2015-05-14 04:23:30 +00:00
OnlinePresence . delete_all ( [ " player_id = ? " , self . id ] )
2015-02-15 13:23:26 +00:00
end
2015-04-11 00:19:53 +00:00
unless online_presences . nil?
online_presences . each do | op |
2016-01-04 19:42:11 +00:00
new_presence = OnlinePresence . create ( self , op , false )
2015-04-11 00:19:53 +00:00
self . online_presences << new_presence
end
2015-02-15 13:23:26 +00:00
end
2015-02-15 02:02:26 +00:00
end
def update_performance_samples ( performance_samples )
2015-02-15 13:23:26 +00:00
unless self . new_record?
2015-05-14 04:23:30 +00:00
PerformanceSample . delete_all ( [ " player_id = ? " , self . id ] )
2015-02-15 13:23:26 +00:00
end
2015-04-11 00:19:53 +00:00
unless performance_samples . nil?
performance_samples . each do | ps |
new_sample = PerformanceSample . create ( self , ps , false )
self . performance_samples << new_sample
end
2015-02-15 13:23:26 +00:00
end
2015-02-15 02:02:26 +00:00
end
2015-07-06 20:34:27 +00:00
# Build calendars using given parameter.
# @param calendars (array of hash)
def update_calendars ( calendars )
unless self . new_record?
Calendar . where ( " user_id = ? " , self . id ) . delete_all
end
unless calendars . nil?
calendars . each do | cal |
self . calendars << self . calendars . create ( cal )
end
end
end
2013-08-29 12:12:38 +00:00
# given an array of instruments, update a user's instruments
def update_instruments ( instruments )
# delete all instruments for this user first
unless self . new_record?
VRFS-3242 : Schema and model changes required for band profile functionality.
* Additional attributes for band_type, band_status, concert_count,
add_new_members, play_commitment, touring_option, paid_gigs,
hourly_rate, gig_minimum
* For joined table musician_instruments, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table performance_stamples, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table online_presences, remove the hard requirement that
they be joined to a user, rather a “player” that is polymorphic.
* Change models as appropriate with new attributes and modify
belongs_to / has_many directives as necessary.
* Fix existing usages of user_id to work with polymorphic player_id.
* Fix tests that use user_id
* Add new tests that exercise online_presence, performance_samples, and
instruments that target a band, rather than a user.
2015-05-14 02:06:14 +00:00
MusicianInstrument . delete_all ( [ " player_id = ? " , self . id ] )
2013-08-29 12:12:38 +00:00
end
# loop through each instrument in the array and save to the db
instruments . each do | musician_instrument_param |
instrument = Instrument . find ( musician_instrument_param [ :instrument_id ] )
musician_instrument = MusicianInstrument . new
VRFS-3242 : Schema and model changes required for band profile functionality.
* Additional attributes for band_type, band_status, concert_count,
add_new_members, play_commitment, touring_option, paid_gigs,
hourly_rate, gig_minimum
* For joined table musician_instruments, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table performance_stamples, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table online_presences, remove the hard requirement that
they be joined to a user, rather a “player” that is polymorphic.
* Change models as appropriate with new attributes and modify
belongs_to / has_many directives as necessary.
* Fix existing usages of user_id to work with polymorphic player_id.
* Fix tests that use user_id
* Add new tests that exercise online_presence, performance_samples, and
instruments that target a band, rather than a user.
2015-05-14 02:06:14 +00:00
musician_instrument . player = self
2013-08-29 12:12:38 +00:00
musician_instrument . instrument = instrument
musician_instrument . proficiency_level = musician_instrument_param [ :proficiency_level ]
musician_instrument . priority = musician_instrument_param [ :priority ]
musician_instrument . save
self . musician_instruments << musician_instrument
end
end
# this easy_save routine guards against nil sets, but many of these fields can be set to null.
# I've started to use it less as I go forward
2013-03-15 04:22:31 +00:00
def easy_save ( first_name , last_name , email , password , password_confirmation , musician , gender ,
2016-01-04 19:42:11 +00:00
birth_date , internet_service_provider , city , state , country , instruments , photo_url , biography = nil )
2012-11-22 08:27:23 +00:00
2012-11-11 04:23:38 +00:00
# first name
2012-11-21 19:48:39 +00:00
unless first_name . nil?
2013-03-15 04:22:31 +00:00
self . first_name = first_name
2012-11-11 04:23:38 +00:00
end
# last name
2012-11-21 19:48:39 +00:00
unless last_name . nil?
2013-03-15 04:22:31 +00:00
self . last_name = last_name
2012-11-11 04:23:38 +00:00
end
2012-11-03 13:54:55 +00:00
# email
2013-05-10 12:10:33 +00:00
# !! Email is changed in a dedicated method, 'update_email'
#unless email.nil?
# self.email = email
#end
2012-11-03 13:54:55 +00:00
# password
2012-11-21 19:48:39 +00:00
unless password . nil?
2013-03-15 04:22:31 +00:00
self . password = password
2012-10-29 10:45:47 +00:00
end
2012-11-03 13:54:55 +00:00
# password confirmation
2012-11-21 19:48:39 +00:00
unless password_confirmation . nil?
2013-03-15 04:22:31 +00:00
self . password_confirmation = password_confirmation
2012-11-03 13:54:55 +00:00
end
# musician flag
2012-11-21 19:48:39 +00:00
unless musician . nil?
2013-03-15 04:22:31 +00:00
self . musician = musician
2012-11-03 13:54:55 +00:00
end
2012-11-13 02:52:05 +00:00
# gender
2012-11-21 19:48:39 +00:00
unless gender . nil?
2013-03-15 04:22:31 +00:00
self . gender = gender
2012-11-13 02:52:05 +00:00
end
# birthdate
2012-11-21 19:48:39 +00:00
unless birth_date . nil?
2013-03-15 04:22:31 +00:00
self . birth_date = birth_date
2012-11-13 02:52:05 +00:00
end
# ISP
2012-11-21 19:48:39 +00:00
unless internet_service_provider . nil?
2013-03-15 04:22:31 +00:00
self . internet_service_provider = internet_service_provider
2012-11-13 02:52:05 +00:00
end
2012-11-06 02:55:08 +00:00
# city
2012-11-21 19:48:39 +00:00
unless city . nil?
2013-03-15 04:22:31 +00:00
self . city = city
2012-11-06 02:55:08 +00:00
end
# state
2012-11-21 19:48:39 +00:00
unless state . nil?
2013-03-15 04:22:31 +00:00
self . state = state
2012-11-06 02:55:08 +00:00
end
# country
2012-11-21 19:48:39 +00:00
unless country . nil?
2013-03-15 04:22:31 +00:00
self . country = country
2012-11-06 02:55:08 +00:00
end
2012-11-03 13:54:55 +00:00
# instruments
2012-11-21 19:48:39 +00:00
unless instruments . nil?
2013-08-29 12:12:38 +00:00
update_instruments ( instruments )
2012-10-29 10:45:47 +00:00
end
2012-11-03 13:54:55 +00:00
2012-11-28 05:26:53 +00:00
# photo url
unless photo_url . nil?
2013-03-15 04:22:31 +00:00
self . photo_url = photo_url
2012-11-28 05:26:53 +00:00
end
2013-11-03 03:35:18 +00:00
unless biography . nil?
self . biography = biography
end
2014-05-01 19:09:33 +00:00
self . updated_at = Time . now
2013-03-15 04:22:31 +00:00
self . save
end
# helper method for creating / updating a User
def self . save ( id , updater_id , first_name , last_name , email , password , password_confirmation , musician , gender ,
2016-01-04 19:42:11 +00:00
birth_date , internet_service_provider , city , state , country , instruments , photo_url , biography )
2013-03-15 04:22:31 +00:00
if id . nil?
user = User . new ( )
else
user = User . find ( id )
end
if user . id != updater_id
2015-04-20 14:50:33 +00:00
raise JamPermissionError , ValidationMessages :: PERMISSION_VALIDATION_ERROR
2016-01-04 19:42:11 +00:00
end
2013-03-15 04:22:31 +00:00
user . easy_save ( first_name , last_name , email , password , password_confirmation , musician , gender ,
2013-11-03 03:35:18 +00:00
birth_date , internet_service_provider , city , state , country , instruments , photo_url , biography )
2012-10-29 10:45:47 +00:00
return user
end
2013-05-14 19:02:22 +00:00
def begin_update_email ( email , current_password , confirmation_url )
2013-05-10 12:10:33 +00:00
# sets the user model in a state such that it's expecting to have it's email updated
# two columns matter for this; 'update_email_token' and 'update_email'
# confirmation_link is odd in the sense that it can likely only come from www.jamkazam.com (jam-web)
# an observer should be set up to send an email based on this activity
2013-05-14 19:02:22 +00:00
self . updating_email = self . confirm_current_password = true
self . current_password = current_password
2013-05-10 12:10:33 +00:00
self . update_email = email
self . update_email_token = SecureRandom . urlsafe_base64
self . update_email_confirmation_url = " #{ confirmation_url } #{ self . update_email_token } "
self . save
end
2014-02-16 01:24:51 +00:00
def create_user_following ( targetUserId )
2014-02-16 07:28:35 +00:00
targetUser = User . find ( targetUserId )
2014-02-16 01:24:51 +00:00
follow = Follow . new
follow . followable = targetUser
follow . user = self
follow . save
2013-12-29 04:51:35 +00:00
# TODO: make this async
2014-02-16 07:28:35 +00:00
Notification . send_new_user_follower ( self , targetUser )
2013-12-29 04:51:35 +00:00
end
2014-02-16 01:24:51 +00:00
def create_band_following ( targetBandId )
2013-12-29 04:51:35 +00:00
2014-02-16 07:28:35 +00:00
targetBand = Band . find ( targetBandId )
2013-12-29 04:51:35 +00:00
2014-02-16 01:24:51 +00:00
follow = Follow . new
follow . followable = targetBand
follow . user = self
follow . save
2013-05-10 12:10:33 +00:00
2014-02-16 01:24:51 +00:00
# TODO: make this async
2014-02-16 07:28:35 +00:00
Notification . send_new_band_follower ( self , targetBand )
2013-05-10 12:10:33 +00:00
end
2014-02-16 07:28:35 +00:00
def self . delete_following ( followerId , targetEntityId )
Follow . delete_all " (user_id = ' #{ followerId } ' AND followable_id = ' #{ targetEntityId } ') "
2012-12-17 06:01:48 +00:00
end
2014-02-16 18:06:36 +00:00
def create_user_liking ( targetUserId )
2014-02-16 07:28:35 +00:00
targetUser = User . find ( targetUserId )
2012-12-17 06:01:48 +00:00
2014-02-16 01:24:51 +00:00
like = Like . new
like . likable = targetUser
like . user = self
like . save
2012-12-17 06:01:48 +00:00
end
2014-02-16 18:06:36 +00:00
def create_band_liking ( targetBandId )
2014-02-16 07:28:35 +00:00
targetBand = Band . find ( targetBandId )
2014-02-16 01:24:51 +00:00
like = Like . new
like . likable = targetBand
like . user = self
like . save
2012-12-17 06:01:48 +00:00
end
2014-02-16 18:06:36 +00:00
def self . delete_liking ( likerId , targetEntityId )
2014-02-16 19:48:54 +00:00
Like . delete_all " (user_id = ' #{ likerId } ' AND likable_id = ' #{ targetEntityId } ') "
2014-02-16 07:28:35 +00:00
end
2014-02-16 18:06:36 +00:00
# def create_session_like(targetSessionId)
2014-05-06 13:34:38 +00:00
# targetSession = MusicSession.find(targetSessionId)
2014-02-16 07:28:35 +00:00
2014-02-16 18:06:36 +00:00
# like = Like.new
# like.likable = targetSession
# like.user = self
# like.save
# end
# def create_recording_like(targetRecordingId)
# targetRecording = Recording.find(targetRecordingId)
2016-01-04 19:42:11 +00:00
2014-02-16 18:06:36 +00:00
# like = Like.new
# like.likable = targetRecording
# like.user = self
# like.save
# end
2012-12-17 06:01:48 +00:00
2014-02-16 01:24:51 +00:00
def self . finalize_update_email ( update_email_token )
# updates the user model to have a new email address
user = User . find_by_update_email_token! ( update_email_token )
2012-12-04 03:39:57 +00:00
2014-02-16 01:24:51 +00:00
user . updated_email = true
user . email = user . update_email
user . update_email_token = nil
user . save
2016-01-04 19:42:11 +00:00
begin
2015-04-01 01:25:23 +00:00
RecurlyClient . new . update_account ( user )
rescue Recurly :: Error
@@log . debug ( " No recurly account found; continuing " )
end
2012-11-21 19:48:39 +00:00
2014-02-16 01:24:51 +00:00
return user
2012-11-21 19:48:39 +00:00
end
def self . create_favorite ( user_id , recording_id )
2013-12-29 04:51:35 +00:00
favorite = UserFavorite . new
2012-11-22 08:27:23 +00:00
favorite . user_id = user_id
favorite . recording_id = recording_id
favorite . save
2012-11-21 19:48:39 +00:00
end
2013-12-19 04:10:55 +00:00
def favorite_count
2016-01-04 19:42:11 +00:00
0 # FIXME: update this with recording likes count when implemented
2013-12-19 04:10:55 +00:00
end
2012-11-21 19:48:39 +00:00
def self . delete_favorite ( user_id , recording_id )
JamRuby :: UserFavorite . delete_all " (user_id = ' #{ user_id } ' AND recording_id = ' #{ recording_id } ') "
end
2012-12-09 04:05:54 +00:00
def self . save_session_settings ( user , music_session )
unless user . nil?
2012-12-10 05:53:21 +00:00
# only save genre id and description
2014-05-06 21:17:26 +00:00
genres = [ { id : music_session . genre . id , description : music_session . genre . description } ]
2012-12-10 05:53:21 +00:00
# only save invitation receiver id and name
invitees = [ ]
unless music_session . invitations . nil?
music_session . invitations . each do | invitation |
i = Hash . new
i [ " id " ] = invitation . receiver . id
i [ " name " ] = invitation . receiver . name
invitees << i
end
end
2016-07-17 15:16:27 +00:00
session_settings = { :band_id = > music_session . band_id ,
:musician_access = > music_session . musician_access ,
:approval_required = > music_session . approval_required ,
:fan_chat = > music_session . fan_chat ,
:fan_access = > music_session . fan_access ,
:description = > music_session . description ,
:genres = > genres ,
:invitees = > invitees
}
2012-12-09 04:05:54 +00:00
user . session_settings = session_settings
user . save
end
end
2016-06-03 04:32:09 +00:00
def handle_test_drive_package ( package , details )
self . test_drive_packaging = true
choice = TestDrivePackageChoice . new
choice . user = self
choice . test_drive_package = package
details [ :teachers ] . each do | teacher |
teacher_choice = TestDrivePackageChoiceTeacher . new
teacher_choice . teacher = User . find ( teacher [ :id ] )
choice . test_drive_package_choice_teachers << teacher_choice
end
choice . save!
choice . test_drive_package_choice_teachers . each do | teacher_choice |
booking = LessonBooking . book_packaged_test_drive ( self , teacher_choice . teacher , " Please suggest a time that works for you. " , choice )
if booking . errors . any?
raise " unable to create booking in package user: #{ self . email } "
end
end
end
2017-03-22 12:39:06 +00:00
def is_guitar_center?
is_guitar_center_student? || is_guitar_center_teacher?
end
def is_guitar_center_student?
! school . nil? && school . is_guitar_center?
end
def is_guitar_center_teacher?
! teacher . nil? && teacher . is_guitar_center?
end
2012-11-21 19:48:39 +00:00
# throws ActiveRecord::RecordNotFound if instrument is invalid
# throws an email delivery error if unable to connect out to SMTP
2014-02-03 21:19:14 +00:00
def self . signup ( options )
first_name = options [ :first_name ]
last_name = options [ :last_name ]
email = options [ :email ]
password = options [ :password ]
password_confirmation = options [ :password_confirmation ]
terms_of_service = options [ :terms_of_service ]
location = options [ :location ]
instruments = options [ :instruments ]
birth_date = options [ :birth_date ]
musician = options [ :musician ]
photo_url = options [ :photo_url ]
invited_user = options [ :invited_user ]
fb_signup = options [ :fb_signup ]
signup_confirm_url = options [ :signup_confirm_url ]
2014-04-20 22:54:49 +00:00
affiliate_referral_id = options [ :affiliate_referral_id ]
2015-01-05 23:01:28 +00:00
recaptcha_failed = options [ :recaptcha_failed ]
2015-03-16 18:27:39 +00:00
any_user = options [ :any_user ]
reuse_card = options [ :reuse_card ]
2015-05-15 17:34:35 +00:00
signup_hint = options [ :signup_hint ]
2015-06-03 19:22:21 +00:00
affiliate_partner = options [ :affiliate_partner ]
2015-11-13 13:12:58 +00:00
gift_card = options [ :gift_card ]
2016-02-11 03:09:45 +00:00
student = options [ :student ]
teacher = options [ :teacher ]
2016-04-06 02:23:15 +00:00
school_invitation_code = options [ :school_invitation_code ]
school_id = options [ :school_id ]
2016-09-27 02:56:12 +00:00
retailer_invitation_code = options [ :retailer_invitation_code ]
retailer_id = options [ :retailer_id ]
2016-10-07 13:28:17 +00:00
retailer_interest = options [ :retailer_interest ]
2016-04-26 03:01:15 +00:00
school_interest = options [ :school_interest ]
2016-09-08 23:06:04 +00:00
education_interest = options [ :education_interest ]
2016-05-23 17:26:32 +00:00
origin = options [ :origin ]
2016-06-03 04:32:09 +00:00
test_drive_package_details = options [ :test_drive_package ]
2017-10-15 21:42:45 +00:00
under_13 = options [ :under_13 ]
2018-02-15 04:16:32 +00:00
timezone = options [ :timezone ]
2016-06-03 04:32:09 +00:00
2016-06-03 13:41:14 +00:00
test_drive_package = TestDrivePackage . find_by_name ( test_drive_package_details [ :name ] ) if test_drive_package_details
2014-02-03 21:19:14 +00:00
2016-05-16 16:39:20 +00:00
school = School . find ( school_id ) if school_id
2016-09-27 02:56:12 +00:00
retailer = School . find ( retailer_id ) if retailer_id
2012-11-21 19:48:39 +00:00
user = User . new
2016-02-08 12:56:54 +00:00
user . validate_instruments = true
2012-11-21 19:48:39 +00:00
UserManager . active_record_transaction do | user_manager |
2016-04-06 02:23:15 +00:00
if school_invitation_code
school_invitation = SchoolInvitation . find_by_invitation_code ( school_invitation_code )
if school_invitation
first_name || = school_invitation . first_name
last_name || = school_invitation . last_name
school_invitation . accepted = true
school_invitation . save
end
end
2016-09-27 02:56:12 +00:00
if retailer_invitation_code
retailer_invitation = RetailerInvitation . find_by_invitation_code ( retailer_invitation_code )
if retailer_invitation
first_name || = retailer_invitation . first_name
last_name || = retailer_invitation . last_name
retailer_invitation . accepted = true
retailer_invitation . save
end
end
2016-04-06 02:23:15 +00:00
user . first_name = first_name if first_name . present?
user . last_name = last_name if last_name . present?
2012-11-21 19:48:39 +00:00
user . email = email
2013-10-22 17:38:21 +00:00
user . subscribe_email = true
2013-03-15 04:22:31 +00:00
user . terms_of_service = terms_of_service
2015-03-16 18:27:39 +00:00
user . reuse_card unless reuse_card . nil?
2015-11-13 13:12:58 +00:00
user . gifted_jamtracks = 0
2016-08-31 09:19:16 +00:00
user . jamclass_credits = 0
2015-11-13 13:12:58 +00:00
user . has_redeemable_jamtrack = true
2017-10-15 21:42:45 +00:00
user . under_13 = under_13
2016-02-11 03:09:45 +00:00
user . is_a_student = ! ! student
user . is_a_teacher = ! ! teacher
2016-10-07 13:28:17 +00:00
user . retailer_interest = ! ! retailer_interest
2016-04-26 03:01:15 +00:00
user . school_interest = ! ! school_interest
2016-09-08 23:06:04 +00:00
user . education_interest = ! ! education_interest
2016-02-11 03:09:45 +00:00
if user . is_a_student || user . is_a_teacher
musician = true
end
user . musician = ! ! musician
2015-11-13 13:12:58 +00:00
2016-05-23 17:26:32 +00:00
if origin
user . origin_utm_source = origin [ " utm_source " ]
user . origin_utm_medium = origin [ " utm_medium " ]
user . origin_utm_campaign = origin [ " utm_campaign " ]
user . origin_referrer = origin [ " referrer " ]
else
user . origin_utm_source = 'organic'
user . origin_utm_medium = 'organic'
user . origin_utm_campaign = nil
user . origin_referrer = nil
end
2016-04-06 02:23:15 +00:00
if school_id . present?
if user . is_a_student
user . school_id = school_id
2016-05-16 16:39:20 +00:00
user . affiliate_referral = school . affiliate_partner
2016-04-06 02:23:15 +00:00
elsif user . is_a_teacher
school = School . find_by_id ( school_id )
2016-06-02 14:04:56 +00:00
user . teacher = Teacher . build_teacher ( user , validate_introduction : true , biography : " Empty biography " , school_id : school_id )
2016-05-16 16:39:20 +00:00
user . affiliate_referral = school . affiliate_partner
2016-04-06 02:23:15 +00:00
end
2016-09-27 02:56:12 +00:00
elsif retailer_id . present?
if user . is_a_student
user . retailer_id = school_id
user . affiliate_referral = retailer . affiliate_partner
elsif user . is_a_teacher
retailer = Retailer . find_by_id ( retailer_id )
user . teacher = Teacher . build_teacher ( user , validate_introduction : true , biography : " Empty biography " , retailer_id : retailer_id )
user . affiliate_referral = retailer . affiliate_partner
end
2016-04-13 22:14:05 +00:00
else
if user . is_a_teacher
user . teacher = Teacher . build_teacher ( user , validate_introduction : true , biography : " Empty biography " )
end
2016-04-06 02:23:15 +00:00
end
2016-04-13 22:14:05 +00:00
2013-03-15 04:22:31 +00:00
# FIXME: Setting random password for social network logins. This
2012-11-21 19:48:39 +00:00
# is because we have validations all over the place on this.
# The right thing would be to have this null
2013-03-15 04:22:31 +00:00
# Seth: I think we need a flag in the signature of signup to say 'social_signup=true'. If that flag is set,
# then you can do use.updating_password = false and instead set a null password
2012-11-21 19:48:39 +00:00
if password . nil?
2016-01-04 19:42:11 +00:00
user . password = user . password_confirmation = SecureRandom . urlsafe_base64
2012-11-21 19:48:39 +00:00
else
user . password = password
user . password_confirmation = password_confirmation
end
2012-11-14 05:37:18 +00:00
2012-11-21 19:48:39 +00:00
user . admin = false
2014-05-13 04:13:16 +00:00
user . location = location
# user.city = location[:city]
# user.state = location[:state]
# user.country = location[:country]
2013-03-15 04:22:31 +00:00
user . birth_date = birth_date
2014-05-09 00:44:52 +00:00
if musician
user . last_jam_addr = location [ :addr ]
user . last_jam_locidispid = location [ :locidispid ]
2014-07-20 02:11:16 +00:00
user . last_jam_updated_reason = JAM_REASON_REGISTRATION
2014-05-09 00:44:52 +00:00
user . last_jam_updated_at = Time . now
end
if musician # only update instruments if the user is a musician
2013-06-22 02:28:42 +00:00
unless instruments . nil?
instruments . each do | musician_instrument_param |
instrument = Instrument . find ( musician_instrument_param [ :instrument_id ] )
musician_instrument = MusicianInstrument . new
VRFS-3242 : Schema and model changes required for band profile functionality.
* Additional attributes for band_type, band_status, concert_count,
add_new_members, play_commitment, touring_option, paid_gigs,
hourly_rate, gig_minimum
* For joined table musician_instruments, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table performance_stamples, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table online_presences, remove the hard requirement that
they be joined to a user, rather a “player” that is polymorphic.
* Change models as appropriate with new attributes and modify
belongs_to / has_many directives as necessary.
* Fix existing usages of user_id to work with polymorphic player_id.
* Fix tests that use user_id
* Add new tests that exercise online_presence, performance_samples, and
instruments that target a band, rather than a user.
2015-05-14 02:06:14 +00:00
musician_instrument . player = user
2013-06-22 02:28:42 +00:00
musician_instrument . instrument = instrument
musician_instrument . proficiency_level = musician_instrument_param [ :proficiency_level ]
musician_instrument . priority = musician_instrument_param [ :priority ]
user . musician_instruments << musician_instrument
end
2012-11-21 19:48:39 +00:00
end
end
2012-11-28 05:26:53 +00:00
user . photo_url = photo_url
2015-03-16 18:27:39 +00:00
# copy over the shopping cart to the new user, if a shopping cart is provided
2015-04-19 16:43:54 +00:00
if any_user
user . shopping_carts = any_user . shopping_carts
if user . shopping_carts
user . shopping_carts . each do | shopping_cart |
shopping_cart . anonymous_user_id = nil # nil out the anonymous user ID; required for uniqeness constraint on ShoppingCart
end
end
end
2014-02-03 21:19:14 +00:00
unless fb_signup . nil?
user . update_fb_authorization ( fb_signup )
if fb_signup . email . casecmp ( user . email ) . zero?
user . email_confirmed = true
user . signup_token = nil
else
user . email_confirmed = false
user . signup_token = SecureRandom . urlsafe_base64
end
end
2012-11-15 09:30:55 +00:00
2013-07-31 15:06:36 +00:00
if invited_user . nil?
2013-03-15 04:22:31 +00:00
user . can_invite = Limits :: USERS_CAN_INVITE
2014-02-03 21:19:14 +00:00
unless user . email_confirmed # important that the only time this goes true is if some other mechanism, like fb_signup, set this high
user . email_confirmed = false
user . signup_token = SecureRandom . urlsafe_base64
end
2013-03-15 04:22:31 +00:00
else
# if you are invited by an admin, we'll say you can invite too.
# but if not, then you can not invite
2014-03-15 16:47:21 +00:00
user . can_invite = Limits :: USERS_CAN_INVITE #invited_user.invited_by_administrator?
2013-03-15 04:22:31 +00:00
# if you came in from an invite and used the same email to signup,
# then we know you are a real human and that your email is valid.
# lucky! we'll log you in immediately
2014-03-21 22:37:15 +00:00
if invited_user . email && invited_user . email . casecmp ( user . email ) . zero?
2013-03-15 04:22:31 +00:00
user . email_confirmed = true
user . signup_token = nil
else
user . email_confirmed = false
user . signup_token = SecureRandom . urlsafe_base64
end
# now that the user is saved, let's
if invited_user . autofriend && ! invited_user . sender . nil?
# hookup this user with the sender
Friendship . save_using_models ( user , invited_user . sender )
end
invited_user . accept!
invited_user . save
if invited_user . errors . any?
raise ActiveRecord :: Rollback
end
end
2013-01-04 10:13:39 +00:00
2015-11-13 13:12:58 +00:00
found_gift_card = nil
# if a gift card value was passed in, then try to find that gift card and apply it to user
if gift_card
2016-08-31 09:19:16 +00:00
# first try posa card
2016-10-03 03:26:47 +00:00
posa_card = PosaCard . where ( code : gift_card ) . first
2016-08-31 09:19:16 +00:00
if posa_card
posa_card . claim ( user )
2017-10-15 22:07:35 +00:00
user . via_amazon = posa_card . is_amazon_posa_card?
2016-08-31 09:19:16 +00:00
user . posa_cards << posa_card
2017-07-10 02:21:29 +00:00
user . purchase_required = posa_card . requires_purchase # temporary; just so the signup page knows to send them to payment place
2016-08-31 09:19:16 +00:00
else
2017-07-10 02:21:29 +00:00
2016-08-31 09:19:16 +00:00
user . expecting_gift_card = true
found_gift_card = GiftCard . where ( code : gift_card ) . where ( user_id : nil ) . first
2017-07-10 02:21:29 +00:00
if found_gift_card
user . gift_cards << found_gift_card
end
2016-08-31 09:19:16 +00:00
end
2015-11-13 13:12:58 +00:00
end
2012-11-21 19:48:39 +00:00
user . save
2012-11-15 09:30:55 +00:00
2015-11-13 13:12:58 +00:00
if found_gift_card
user . reload
ShoppingCart . apply_gifted_jamtracks ( user )
end
2015-05-15 17:34:35 +00:00
# if the user has just one, free jamtrack in their shopping cart, and it matches the signup hint, then auto-buy it
# only_freebie_in_cart =
# signup_hint &&
# signup_hint.jam_track &&
# user.shopping_carts.length == 1 &&
# user.shopping_carts[0].cart_product == signup_hint.jam_track &&
# user.shopping_carts[0].product_info[:free]
#
# if only_freebie_in_cart
# Sale.place_order(user, user.shopping_carts)
# end
2015-01-12 17:34:06 +00:00
user . errors . add ( " recaptcha " , " verification failed " ) if recaptcha_failed
2016-01-04 19:42:11 +00:00
unless user . errors . any?
if Rails . application . config . verify_email_enabled
client = Kickbox :: Client . new ( Rails . application . config . kickbox_api_key )
kickbox = client . kickbox ( )
response = kickbox . verify ( email )
result = response . body [ " result " ]
user . kickbox_response = response . body . to_json
if result == " deliverable "
user . email_needs_verification = false
elsif result == " undeliverable "
did_you_mean = response . body [ " did_you_mean " ]
if did_you_mean
user . errors . add ( :email , " Did you mean #{ did_you_mean } ? " )
else
user . errors . add ( :email , " is not real " )
end
elsif result == " risky " || result == " unknown "
2016-02-01 20:14:06 +00:00
if response . body [ " disposable " ]
user . errors . add ( :email , " is disposable address " )
else
user . email_needs_verification = true
end
2016-01-04 19:42:11 +00:00
end
else
user . email_needs_verification = false
end
end
user . save unless user . errors . any?
2012-11-21 19:48:39 +00:00
if user . errors . any?
raise ActiveRecord :: Rollback
else
2015-06-03 19:22:21 +00:00
# if the partner ID was present and the partner doesn't already have a user associated, associate this new user with the affiliate partner
if affiliate_partner && affiliate_partner . partner_user . nil?
affiliate_partner . partner_user = user
unless affiliate_partner . save
@@log . error ( " unable to associate #{ user . to_s } with affiliate_partner #{ affiliate_partner . id } / #{ affiliate_partner . partner_name } " )
end
end
2014-04-20 22:54:49 +00:00
if user . affiliate_referral = AffiliatePartner . find_by_id ( affiliate_referral_id )
user . save
end if affiliate_referral_id . present?
2016-07-17 15:16:27 +00:00
2016-06-03 04:32:09 +00:00
user . handle_test_drive_package ( test_drive_package , test_drive_package_details ) if test_drive_package
2016-04-06 02:23:15 +00:00
if user . is_a_student
2016-09-09 14:06:02 +00:00
#if school && school.education
# UserMailer.student_education_welcome_message(user).deliver_now
#else
2017-07-10 02:21:29 +00:00
body = " Name: #{ user . name } \n "
body << " Email: #{ user . email } \n "
2018-01-17 03:29:43 +00:00
body << " Student List: #{ user . admin_student_url } \n "
body << " User Page: #{ user . admin_url } \n "
2017-07-10 02:21:29 +00:00
if posa_card
body << " Package Details: \n "
body << " Package: #{ posa_card . lesson_package_type . id } \n "
body << " Credits: #{ posa_card . credits } \n "
body << " Code: #{ posa_card . code } \n "
end
2017-10-15 21:42:45 +00:00
AdminMailer . jamclass_alerts ( { subject : " #{ user . email } just signed up as a student " , body : body } ) . deliver_now
2017-10-15 22:07:35 +00:00
if user . via_amazon
UserMailer . amazon_welcome_message ( user ) . deliver_now
2018-05-27 14:46:06 +00:00
user . send_lesson_poke ( true )
2017-10-15 22:07:35 +00:00
else
UserMailer . student_welcome_message ( user ) . deliver_now
end
2016-09-09 14:06:02 +00:00
#end
2016-05-10 01:13:06 +00:00
elsif user . is_a_teacher
2016-07-17 15:16:27 +00:00
UserMailer . teacher_welcome_message ( user ) . deliver_now
2016-09-08 23:06:04 +00:00
elsif user . education_interest
UserMailer . education_owner_welcome_message ( user ) . deliver_now
2016-05-10 01:13:06 +00:00
elsif user . school_interest
2016-07-17 15:16:27 +00:00
UserMailer . school_owner_welcome_message ( user ) . deliver_now
2016-10-07 13:28:17 +00:00
elsif user . retailer_interest
UserMailer . retailer_owner_welcome_message ( user ) . deliver_now
2016-05-10 01:13:06 +00:00
else
2016-07-17 15:16:27 +00:00
UserMailer . welcome_message ( user ) . deliver_now
2016-04-06 02:23:15 +00:00
end
if ! user . email_confirmed
2013-03-15 04:22:31 +00:00
# any errors here should also rollback the transaction; that's OK. If emails aren't going to be delivered,
# it's already a really bad situation; make user signup again
2016-07-17 15:16:27 +00:00
UserMailer . confirm_email ( user , signup_confirm_url . nil? ? nil : ( signup_confirm_url + " / " + user . signup_token ) ) . deliver_now
2013-03-15 04:22:31 +00:00
end
2012-11-14 05:37:18 +00:00
end
end
2018-02-15 04:16:32 +00:00
user . update_timezone ( timezone )
2016-01-04 19:42:11 +00:00
user . reload if user . id # gift card adding gifted_jamtracks doesn't reflect here until reload
2015-01-12 17:34:06 +00:00
user
2016-01-04 19:42:11 +00:00
end
# def signup
2012-11-14 05:37:18 +00:00
2017-03-22 12:39:06 +00:00
def self . create_user ( first_name , last_name , email , password , city , state , country , instruments , photo_url )
2012-12-09 20:56:35 +00:00
2016-07-17 15:16:27 +00:00
user = User . find_or_create_by ( { email : email } )
2012-12-09 20:56:35 +00:00
User . transaction do
user . first_name = first_name
user . last_name = last_name
user . email = email
user . password = password
user . password_confirmation = password
user . admin = true
user . email_confirmed = true
user . musician = true
user . city = city
user . state = state
user . country = country
2013-03-15 04:22:31 +00:00
user . terms_of_service = true
2012-12-09 20:56:35 +00:00
if instruments . nil?
instruments = [ { :instrument_id = > " acoustic guitar " , :proficiency_level = > 3 , :priority = > 1 } ]
end
unless user . new_record?
VRFS-3242 : Schema and model changes required for band profile functionality.
* Additional attributes for band_type, band_status, concert_count,
add_new_members, play_commitment, touring_option, paid_gigs,
hourly_rate, gig_minimum
* For joined table musician_instruments, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table performance_stamples, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table online_presences, remove the hard requirement that
they be joined to a user, rather a “player” that is polymorphic.
* Change models as appropriate with new attributes and modify
belongs_to / has_many directives as necessary.
* Fix existing usages of user_id to work with polymorphic player_id.
* Fix tests that use user_id
* Add new tests that exercise online_presence, performance_samples, and
instruments that target a band, rather than a user.
2015-05-14 02:06:14 +00:00
MusicianInstrument . delete_all ( [ " player_id = ? " , user . id ] )
2012-12-09 20:56:35 +00:00
end
instruments . each do | musician_instrument_param |
instrument = Instrument . find ( musician_instrument_param [ :instrument_id ] )
musician_instrument = MusicianInstrument . new
VRFS-3242 : Schema and model changes required for band profile functionality.
* Additional attributes for band_type, band_status, concert_count,
add_new_members, play_commitment, touring_option, paid_gigs,
hourly_rate, gig_minimum
* For joined table musician_instruments, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table performance_stamples, remove the hard requirement
that they be joined to a user, rather a “player” that is polymorphic.
* For joined table online_presences, remove the hard requirement that
they be joined to a user, rather a “player” that is polymorphic.
* Change models as appropriate with new attributes and modify
belongs_to / has_many directives as necessary.
* Fix existing usages of user_id to work with polymorphic player_id.
* Fix tests that use user_id
* Add new tests that exercise online_presence, performance_samples, and
instruments that target a band, rather than a user.
2015-05-14 02:06:14 +00:00
musician_instrument . player = user
2012-12-09 20:56:35 +00:00
musician_instrument . instrument = instrument
musician_instrument . proficiency_level = musician_instrument_param [ :proficiency_level ]
musician_instrument . priority = musician_instrument_param [ :priority ]
user . musician_instruments << musician_instrument
end
2013-05-31 01:59:37 +00:00
if photo_url . nil?
user . photo_url = photo_url
end
2012-12-09 20:56:35 +00:00
user . signup_token = nil
user . save
if user . errors . any?
raise ActiveRecord :: Rollback
end
end
return user
end
2017-03-22 12:39:06 +00:00
# We guard against this code running in production mode,
# because otherwise it's a bit of uncomfortable code
# to have sitting around
def self . create_dev_user ( first_name , last_name , email , password ,
city , state , country , instruments , photo_url )
if Environment . mode == " production "
# short-circuit out
return
end
return create_user ( first_name , last_name , email , password , city , state , country , instruments , photo_url )
end
2013-03-15 04:22:31 +00:00
def signup_confirm
self . signup_token = nil
self . confirm_email!
self . save
end
2014-09-22 19:20:58 +00:00
# gets the GeoIpLocation for the user's last_jam_locidispid (where are they REALLY, vs profile info)
def geoiplocation
GeoIpLocations . find_by_locid ( last_jam_locidispid / 1000000 ) if last_jam_locidispid
end
2014-07-20 02:11:16 +00:00
def update_last_jam ( remote_ip , reason )
location = GeoIpLocations . lookup ( remote_ip )
self . last_jam_addr = location [ :addr ]
self . last_jam_locidispid = location [ :locidispid ]
self . last_jam_updated_reason = reason
self . last_jam_updated_at = Time . now
save!
end
2014-07-22 19:36:45 +00:00
def update_addr_loc ( connection , reason )
unless connection
@@log . warn ( " no connection specified in update_addr_loc with reason #{ reason } " )
return
end
2014-09-26 04:13:34 +00:00
if connection . locidispid . nil?
@@log . warn ( " no locidispid for connection's ip_address: #{ connection . ip_address } " )
return
end
2014-07-22 19:36:45 +00:00
# we don't use a websocket login to update the user's record unless there is no addr
if reason == JAM_REASON_LOGIN && last_jam_addr
return
end
self . last_jam_addr = connection . addr
self . last_jam_locidispid = connection . locidispid
self . last_jam_updated_reason = reason
self . last_jam_updated_at = Time . now
unless self . save
@@log . warn ( " unable to update user #{ self } with last_jam_reason #{ reason } . errors: #{ self . errors . inspect } " )
end
end
2014-02-07 23:56:39 +00:00
def escape_filename ( path )
dir = File . dirname ( path )
file = File . basename ( path )
" #{ dir } / #{ ERB :: Util . url_encode ( file ) } "
end
2018-02-15 04:16:32 +00:00
def permanently_delete
original_email = self . email
AdminMailer . ugly ( { to : original_email , cc : 'support@jamkazam.com' , subject : 'Your account has been deleted!' , body : " This will be the last email you receive from JamKazam. \n \n Regards, \n Team JamKazam " } ) . deliver_now
User . where ( id : self . id ) . update_all ( encrypted_password : SecureRandom . uuid , email : " deleted+ #{ SecureRandom . uuid } @jamkazam.com " , subscribe_email : false , remember_token : SecureRandom . uuid , deleted : true )
end
2014-02-06 16:31:52 +00:00
def update_avatar ( original_fpfile , cropped_fpfile , cropped_large_fpfile , crop_selection , aws_bucket )
2013-05-31 01:59:37 +00:00
self . updating_avatar = true
cropped_s3_path = cropped_fpfile [ " key " ]
2014-02-06 16:31:52 +00:00
cropped_large_s3_path = cropped_large_fpfile [ " key " ]
2013-05-31 01:59:37 +00:00
2014-02-07 23:56:39 +00:00
self . update_attributes (
2016-01-04 19:42:11 +00:00
:original_fpfile = > original_fpfile ,
:cropped_fpfile = > cropped_fpfile ,
:cropped_large_fpfile = > cropped_large_fpfile ,
:cropped_s3_path = > cropped_s3_path ,
:cropped_large_s3_path = > cropped_large_s3_path ,
:crop_selection = > crop_selection ,
:photo_url = > S3Util . url ( aws_bucket , escape_filename ( cropped_s3_path ) , :secure = > true ) ,
:large_photo_url = > S3Util . url ( aws_bucket , escape_filename ( cropped_large_s3_path ) , :secure = > true )
)
2013-05-31 01:59:37 +00:00
end
def delete_avatar ( aws_bucket )
User . 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 )
2014-02-06 16:31:52 +00:00
S3Util . delete ( aws_bucket , self . cropped_large_s3_path )
2013-05-31 01:59:37 +00:00
end
return self . update_attributes (
:original_fpfile = > nil ,
:cropped_fpfile = > nil ,
2014-02-06 16:31:52 +00:00
:cropped_large_fpfile = > nil ,
2013-05-31 01:59:37 +00:00
:cropped_s3_path = > nil ,
2014-02-06 16:31:52 +00:00
:cropped_large_s3_path = > nil ,
2013-05-31 01:59:37 +00:00
:photo_url = > nil ,
2014-02-06 16:31:52 +00:00
:crop_selection = > nil ,
:large_photo_url = > nil
2013-05-31 01:59:37 +00:00
)
end
end
2012-11-21 19:48:39 +00:00
# throws RecordNotFound if signup token is invalid; i.e., if it's nil, empty string, or not belonging to a user
def self . signup_confirm ( signup_token )
if signup_token . nil? || signup_token . empty?
# there are plenty of confirmed users with nil signup_tokens, so we can't look on it
raise ActiveRecord :: RecordNotFound
2012-11-14 05:37:18 +00:00
else
2016-02-08 12:56:54 +00:00
User . transaction do
2012-11-21 19:48:39 +00:00
# throws ActiveRecord::RecordNotFound if invalid
user = User . find_by_signup_token! ( signup_token )
2013-03-15 04:22:31 +00:00
user . signup_confirm
2012-11-21 19:48:39 +00:00
return user
end
2012-11-14 05:37:18 +00:00
end
end
2012-11-21 19:48:39 +00:00
# if valid credentials are supplied for an 'active' user, returns the user
# if not authenticated, returns nil
def self . authenticate ( email , password )
2013-06-22 02:28:42 +00:00
# remove email_confirmed restriction due to VRFS-378
2012-11-21 19:48:39 +00:00
# we only allow users that have confirmed email to authenticate
2013-06-22 02:28:42 +00:00
# user = User.where('email_confirmed=true').find_by_email(email)
2013-07-10 20:18:25 +00:00
# do a case insensitive search for email, because we store it case sensitive
user = User . where ( " email ILIKE ? " , email ) . first
2012-11-14 05:37:18 +00:00
2013-03-15 04:22:31 +00:00
if user && user . valid_password? ( password )
2012-11-14 05:37:18 +00:00
return user
2012-11-21 19:48:39 +00:00
else
return nil
2012-11-14 05:37:18 +00:00
end
end
2014-02-07 14:07:08 +00:00
def invalidate_user_authorization ( provider )
auth = user_authorization ( provider )
auth . destroy if auth
end
def user_authorization ( provider )
user_authorizations . where ( provider : provider ) . first
end
def auth_twitter
! user_authorization ( 'twitter' ) . nil?
end
2014-02-07 17:18:57 +00:00
def build_twitter_authorization ( auth_hash )
2014-02-07 14:07:08 +00:00
twitter_uid = auth_hash [ :uid ]
credentials = auth_hash [ :credentials ]
secret = credentials [ :secret ] if credentials
token = credentials [ :token ] if credentials
if twitter_uid && secret && token
user_authorization = nil
unless self . new_record?
# see if this user has an existing user_authorization for this provider
user_authorization = UserAuthorization . find_by_user_id_and_provider ( self . id , 'twitter' )
end
end
if user_authorization . nil?
2014-02-07 17:18:57 +00:00
user_authorization = UserAuthorization . new ( provider : 'twitter' ,
2016-01-04 19:42:11 +00:00
uid : twitter_uid ,
token : token ,
secret : secret ,
user : self )
2014-02-07 14:07:08 +00:00
else
user_authorization . uid = twitter_uid
user_authorization . token = token
user_authorization . secret = secret
end
2014-02-07 17:18:57 +00:00
user_authorization
2014-02-07 14:07:08 +00:00
end
2014-02-03 21:19:14 +00:00
# updates an existing user_authorization for facebook, or creates a new one if none exist
def update_fb_authorization ( fb_signup )
if fb_signup . uid && fb_signup . token && fb_signup . token_expires_at
user_authorization = nil
unless self . new_record?
# see if this user has an existing user_authorization for this provider
user_authorization = UserAuthorization . find_by_user_id_and_provider ( self . id , 'facebook' )
end
if user_authorization . nil?
self . user_authorizations . build provider : 'facebook' ,
uid : fb_signup . uid ,
token : fb_signup . token ,
2014-02-07 17:18:57 +00:00
token_expiration : fb_signup . token_expires_at ,
user : self
2014-02-03 21:19:14 +00:00
else
user_authorization . uid = fb_signup . uid
user_authorization . token = fb_signup . token
user_authorization . token_expiration = fb_signup . token_expires_at
2014-02-07 17:18:57 +00:00
user_authorization . save
2014-02-03 21:19:14 +00:00
end
end
end
2013-10-28 14:22:06 +00:00
def provides_location?
! self . city . blank? && ( ! self . state . blank? || ! self . country . blank? )
end
2014-07-20 02:11:16 +00:00
def self . update_locidispids ( use_copied = true )
# using last_jam_addr, we can rebuild
# * last_jam_locidispid
# * last_jam_updated_reason
# * last_jam_updated_at
# this will set a user's last_jam_locidispid = NULL if there are no geoiplocations/blocks that match their IP address, or if there are no JamIsps that match the IP address
# otherwise, last_jam_locidispid will be updated to the correct new value.
# updates all user's locidispids
table_suffix = use_copied ? '_copied' : ''
User . connection . execute ( " UPDATE users SET last_jam_locidispid = (SELECT geolocs.locid as geolocid FROM geoipblocks #{ table_suffix } as geoblocks INNER JOIN geoiplocations #{ table_suffix } AS geolocs ON geoblocks.locid = geolocs.locid WHERE geoblocks.geom && ST_MakePoint(users.last_jam_addr, 0) AND users.last_jam_addr BETWEEN geoblocks.beginip AND geoblocks.endip LIMIT 1) * 1000000::bigint +(SELECT coid FROM jamisp #{ table_suffix } as jisp WHERE geom && ST_MakePoint(users.last_jam_addr, 0) AND users.last_jam_addr BETWEEN beginip AND endip LIMIT 1), last_jam_updated_at = NOW(), last_jam_updated_reason='i' " ) . check
end
def self . after_maxmind_import
update_locidispids
end
2016-01-04 19:42:11 +00:00
2014-05-17 19:55:26 +00:00
# def check_lat_lng
# if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
# update_lat_lng
# end
# end
2013-10-28 14:22:06 +00:00
2014-05-17 19:55:26 +00:00
# def update_lat_lng(ip_addy=nil)
# if provides_location? # ip_addy argument ignored in this case
# return false unless ip_addy.nil? # do nothing if attempting to set latlng from an ip address
# query = { :city => self.city }
# query[:region] = self.state unless self.state.blank?
# query[:country] = self.country unless self.country.blank?
# if geo = MaxMindGeo.where(query).limit(1).first
# geo.lat = nil if geo.lat = 0
# geo.lng = nil if geo.lng = 0
# if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng)
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
# return true
# end
# end
# elsif ip_addy
# if geo = MaxMindGeo.ip_lookup(ip_addy)
# geo.lat = nil if geo.lat = 0
# geo.lng = nil if geo.lng = 0
# if self.lat != geo.lat || self.lng != geo.lng
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
# return true
# end
# end
# else
# if self.lat || self.lng
# self.update_attributes({ :lat => nil, :lng => nil })
# return true
# end
# end
# false
# end
2013-10-28 14:22:06 +00:00
2013-11-04 05:42:41 +00:00
def current_city ( ip_addy = nil )
2014-05-17 19:55:26 +00:00
# unless self.city
# if self.lat && self.lng
# # todo this is really dumb, you can't compare lat lng for equality
# return MaxMindGeo.where(['lat = ? AND lng = ?',self.lat,self.lng]).limit(1).first.try(:city)
# elsif ip_addy
# return MaxMindGeo.ip_lookup(ip_addy).try(:city)
# end
# else
# return self.city
# end
self . city
2013-11-04 05:42:41 +00:00
end
2014-06-09 20:43:16 +00:00
def update_audio_latency ( connection , audio_latency )
2015-01-16 23:20:07 +00:00
# the backend sometimes gives tiny numbers, and sometimes very large numbers
if audio_latency > MINIMUM_AUDIO_LATENCY && audio_latency < MAXIMUM_AUDIO_LATENCY
# updating the connection is best effort; if it's not there that's OK
2014-08-18 15:37:55 +00:00
if connection
2014-10-06 21:44:30 +00:00
Connection . where ( :id = > connection . id ) . update_all ( :last_jam_audio_latency = > audio_latency )
2014-08-18 15:37:55 +00:00
end
2014-06-09 20:43:16 +00:00
2014-08-18 15:37:55 +00:00
self . last_jam_audio_latency = audio_latency
self . save
2014-06-09 20:43:16 +00:00
end
end
2013-11-15 19:52:06 +00:00
def top_followings
2014-02-18 06:12:47 +00:00
@topf || = User . joins ( " INNER JOIN follows ON follows.followable_id = users.id AND follows.followable_type = ' #{ self . class . to_s } ' " )
2016-01-04 19:42:11 +00:00
. where ( [ 'follows.user_id = ?' , self . id ] )
. order ( 'follows.created_at DESC' )
. limit ( 3 )
2013-11-15 19:52:06 +00:00
end
2013-11-26 06:03:42 +00:00
2014-05-16 07:58:06 +00:00
def nearest_musicians
# FIXME: replace with Scotts scoring query
Search . new_musicians ( self , Time . now - 1 . week )
end
2013-11-28 05:35:16 +00:00
def self . deliver_new_musician_notifications ( since_date = nil )
since_date || = Time . now - 1 . week
2014-05-26 19:16:01 +00:00
# return musicians with locidispid not null
self . musicians_geocoded . find_each do | usr |
Search . new_musicians ( usr , since_date ) do | new_nearby |
2016-07-17 15:16:27 +00:00
UserMailer . new_musicians ( usr , new_nearby ) . deliver_now
2014-05-26 19:16:01 +00:00
end
end
2013-11-26 06:03:42 +00:00
end
2013-12-22 05:23:33 +00:00
2014-01-30 03:37:49 +00:00
def facebook_invite!
2014-01-30 03:22:37 +00:00
unless iu = InvitedUser . facebook_invite ( self )
iu = InvitedUser . new
iu . sender = self
iu . autofriend = true
iu . invite_medium = InvitedUser :: FB_MEDIUM
iu . save
end
iu
end
2014-01-30 21:53:22 +00:00
2014-02-13 16:41:50 +00:00
# both email and name helps someone understand/recall/verify who they are looking at
def autocomplete_display_name
" #{ email } ( #{ name } ) "
end
# used by formtastic for display
def to_label
autocomplete_display_name
end
2013-03-15 04:22:31 +00:00
# devise compatibility
2012-11-25 19:37:54 +00:00
2013-03-15 04:22:31 +00:00
#def encrypted_password
# logger.debug("password digest returned #{self.password_digest}")
# self.password_digest
#end
2012-11-25 19:37:54 +00:00
2013-03-15 04:22:31 +00:00
#def encrypted_password=(encrypted_password)
# self.password_digest = encrypted_password
#end
2012-11-25 19:37:54 +00:00
2014-04-07 07:54:17 +00:00
def self . id_for_email ( email )
User . where ( :email = > email ) . limit ( 1 ) . pluck ( :id ) . first
end
2014-07-10 20:57:48 +00:00
# checks if user has submitted RSVP to a session
2014-06-23 04:58:37 +00:00
def has_rsvp ( session )
slots = RsvpSlot . find_by_sql ( %Q{ select rs.*
from rsvp_slots rs
inner join rsvp_requests_rsvp_slots rrrs on rrrs . rsvp_slot_id = rs . id
inner join rsvp_requests rr on rr . id = rrrs . rsvp_request_id
where rs . music_session_id = '#{session.id}'
and rr . user_id = '#{self.id}'
} )
! slots . blank?
end
2014-06-14 17:13:45 +00:00
def has_approved_rsvp ( session )
approved_slots = RsvpSlot . find_by_sql ( %Q{ select rs.*
from rsvp_slots rs
inner join rsvp_requests_rsvp_slots rrrs on rrrs . rsvp_slot_id = rs . id
inner join rsvp_requests rr on rr . id = rrrs . rsvp_request_id
where rs . music_session_id = '#{session.id}'
and rr . user_id = '#{self.id}'
and rrrs . chosen = true
} )
! approved_slots . blank?
end
2016-01-04 19:42:11 +00:00
2013-03-15 04:22:31 +00:00
# end devise compatibility
2014-12-30 23:10:16 +00:00
def self . stats
stats = { }
2016-07-17 15:16:27 +00:00
result = User . select ( 'count(CASE WHEN musician THEN 1 ELSE null END) as musician_count, count(CASE WHEN musician = FALSE THEN 1 ELSE null END) as fan_count, count(first_downloaded_client_at) first_downloaded_client_at_count, count(first_ran_client_at) first_ran_client_at_count, count(first_certified_gear_at) first_certified_gear_at_count, count(first_music_session_at) as first_music_session_at_count, count(first_invited_at) first_invited_at_count, count(first_friended_at) as first_friended_at_count, count(first_social_promoted_at) first_social_promoted_at_count, avg(last_jam_audio_latency) last_jam_audio_latency_avg' ) [ 0 ]
2014-12-30 23:10:16 +00:00
stats [ 'musicians' ] = result [ 'musician_count' ] . to_i
stats [ 'fans' ] = result [ 'fan_count' ] . to_i
stats [ 'downloaded_client' ] = result [ 'first_downloaded_client_at_count' ] . to_i
stats [ 'ran_client' ] = result [ 'first_ran_client_at_count' ] . to_i
stats [ 'certified_gear' ] = result [ 'first_certified_gear_at_count' ] . to_i
stats [ 'jammed' ] = result [ 'first_music_session_at_count' ] . to_i
stats [ 'invited' ] = result [ 'first_invited_at_count' ] . to_i
stats [ 'friended' ] = result [ 'first_friended_at_count' ] . to_i
stats [ 'social_promoted' ] = result [ 'first_social_promoted_at_count' ] . to_i
stats [ 'audio_latency_avg' ] = result [ 'last_jam_audio_latency_avg' ] . to_f
stats
end
2015-03-12 01:55:11 +00:00
2016-12-15 18:47:08 +00:00
def shopping_cart_total
total = 0
shopping_carts . each do | shopping_cart |
total += shopping_cart . product_info [ :total_price ]
end
total
end
2015-03-12 01:55:11 +00:00
def destroy_all_shopping_carts
ShoppingCart . where ( " user_id=? " , self ) . destroy_all
end
2016-08-03 01:46:15 +00:00
def mixed_cart
Sale . is_mixed ( shopping_carts )
end
2015-11-29 19:58:10 +00:00
def destroy_jam_track_shopping_carts
ShoppingCart . destroy_all ( anonymous_user_id : @id , cart_type : JamTrack :: PRODUCT_TYPE )
end
2015-04-12 06:18:31 +00:00
def unsubscribe_token
self . class . create_access_token ( self )
end
# Verifier based on our application secret
def self . verifier
ActiveSupport :: MessageVerifier . new ( APP_CONFIG . secret_token )
end
# Get a user from a token
def self . read_access_token ( signature )
uid = self . verifier . verify ( signature )
User . find_by_id uid
rescue ActiveSupport :: MessageVerifier :: InvalidSignature
nil
end
# Class method for token generation
def self . create_access_token ( user )
verifier . generate ( user . id )
end
2016-07-10 01:48:22 +00:00
def admin_name
" #{ name } ( #{ ( email ) } ) "
end
2015-04-23 15:34:17 +00:00
# URL to jam-admin
def admin_url
APP_CONFIG . admin_root_url + " /admin/users/ " + id
end
2017-07-10 02:21:29 +00:00
def admin_student_url
APP_CONFIG . admin_root_url + " /admin/students " # should add id; not yet supported
end
2018-01-23 03:50:45 +00:00
def admin_onboarding_url
2018-03-29 11:55:11 +00:00
APP_CONFIG . admin_root_url + " /admin/onboarder_managements "
2018-01-23 03:50:45 +00:00
end
2015-04-23 21:20:21 +00:00
def jam_track_rights_admin_url
APP_CONFIG . admin_root_url + " /admin/jam_track_rights?q[user_id_equals]= #{ id } &commit=Filter&order=created_at DESC "
end
2015-05-15 17:34:35 +00:00
# these are signup attributes that we default to when not presenting the typical form @ /signup
def self . musician_defaults ( remote_ip , confirmation_url , any_user , options )
options = options || { }
options [ :remote_ip ] = remote_ip
options [ :birth_date ] = nil
options [ :instruments ] = [ { :instrument_id = > 'other' , :proficiency_level = > 1 , :priority = > 1 } ]
options [ :musician ] = true
options [ :skip_recaptcha ] = true
options [ :invited_user ] = nil
options [ :fb_signup ] = nil
options [ :signup_confirm_url ] = confirmation_url
options [ :any_user ] = any_user
options
end
2016-04-06 02:23:15 +00:00
def should_attribute_sale? ( shopping_cart , instance = nil )
if shopping_cart . is_lesson? && shopping_cart . cart_product . is_test_drive?
# never attribute test drives
return false
end
2016-05-16 16:39:20 +00:00
2015-06-03 19:22:21 +00:00
if affiliate_referral
2016-04-06 02:23:15 +00:00
referral_info = affiliate_referral . should_attribute_sale? ( shopping_cart , self , instance )
2015-06-03 19:22:21 +00:00
else
false
end
end
2016-01-03 17:38:30 +00:00
def redeem_free_credit
2016-01-28 17:31:57 +00:00
using_free_credit = false
2016-01-03 17:38:30 +00:00
if self . has_redeemable_jamtrack
User . where ( id : self . id ) . update_all ( has_redeemable_jamtrack : false )
self . has_redeemable_jamtrack = false
2016-01-28 17:31:57 +00:00
using_free_credit = true
2016-01-03 17:38:30 +00:00
elsif 0 < self . gifted_jamtracks
User . where ( id : self . id ) . update_all ( gifted_jamtracks : self . gifted_jamtracks - 1 )
self . gifted_jamtracks = self . gifted_jamtracks - 1
2016-01-28 17:31:57 +00:00
using_free_credit = true
2016-01-03 17:38:30 +00:00
end
2016-01-28 17:31:57 +00:00
using_free_credit
2016-01-03 17:38:30 +00:00
end
2016-04-06 02:23:15 +00:00
def has_stored_credit_card?
stored_credit_card
end
def has_free_lessons?
remaining_free_lessons > 0
end
def can_book_free_lesson?
has_free_lessons? && has_stored_credit_card?
end
def can_buy_test_drive?
2016-05-05 02:20:38 +00:00
lesson_purchases . where ( 'lesson_package_type_id in (?)' , LessonPackageType . test_drive_package_ids ) . where ( 'created_at > ?' , APP_CONFIG . test_drive_wait_period_year . years . ago ) . count == 0
2016-04-06 02:23:15 +00:00
end
2016-08-31 09:19:16 +00:00
# validate if within waiting period
def can_claim_posa_card
2017-07-10 02:21:29 +00:00
posa_cards . where ( 'is_lesson = ?' , true ) . where ( 'claimed_at > ?' , APP_CONFIG . jam_class_card_wait_period_year . years . ago ) . count == 0
2016-08-31 09:19:16 +00:00
end
2016-05-28 02:33:26 +00:00
def lessons_with_teacher ( teacher )
taken_lessons . where ( teacher_id : teacher . id )
end
def lessons_with_student ( student )
taught_lessons . where ( user_id : student . id )
end
2016-04-06 02:23:15 +00:00
def has_test_drives?
remaining_test_drives > 0
end
2016-09-27 02:56:12 +00:00
def has_posa_credits?
jamclass_credits > 0
end
2016-04-06 02:23:15 +00:00
def has_unprocessed_test_drives?
! unprocessed_test_drive . nil?
end
def has_requested_test_drive? ( teacher = nil )
! requested_test_drive ( teacher ) . nil?
end
2016-04-21 14:23:29 +00:00
def stripe_auth
user_authorizations . where ( provider : " stripe_connect " ) . first
end
2016-12-15 18:47:08 +00:00
def paypal_auth
user_authorizations . where ( provider : 'paypal' ) . first
end
def has_paypal_auth?
auth = paypal_auth
auth && ( ! auth . token_expiration || auth . token_expiration > Time . now )
end
2016-04-21 14:23:29 +00:00
def has_stripe_connect?
auth = stripe_auth
auth && ( ! auth . token_expiration || auth . token_expiration > Time . now )
end
2016-04-06 02:23:15 +00:00
def fetch_stripe_customer
Stripe :: Customer . retrieve ( stripe_customer_id )
end
# if the user already has a stripe customer, then keep it synced. otherwise create it
def sync_stripe_customer
if self . stripe_customer_id
# we already have a customer for this user; re-use it
customer = fetch_stripe_customer
if customer . email . nil? || customer . email . downcase != email . downcase
customer . email = email
customer . save
end
else
customer = Stripe :: Customer . create (
:description = > admin_url ,
:source = > stripe_token ,
:email = > email )
end
self . stripe_customer_id = customer . id
User . where ( id : id ) . update_all ( stripe_customer_id : customer . id )
customer
end
2016-05-05 02:20:38 +00:00
2016-09-08 10:59:58 +00:00
## !!!! this is only valid for tests
def stripe_account_id = ( new_acct_id )
existing = stripe_auth
existing . destroy if existing
user_auth_hash = {
:provider = > 'stripe_connect' ,
:uid = > new_acct_id ,
:token = > 'bogus' ,
:refresh_token = > 'refresh_bogus' ,
:token_expiration = > Date . new ( 2050 , 1 , 1 ) ,
:secret = > " secret "
}
authorization = user_authorizations . build ( user_auth_hash )
authorization . save!
end
2016-06-03 04:32:09 +00:00
def card_approved ( token , zip , booking_id , test_drive_package_choice_id = nil )
2016-04-06 02:23:15 +00:00
approved_booking = nil
2016-06-03 04:32:09 +00:00
choice = nil
2016-05-11 21:03:55 +00:00
found_uncollectables = nil
2016-04-06 02:23:15 +00:00
User . transaction do
self . stripe_token = token if token
self . stripe_zip_code = zip if zip
customer = sync_stripe_customer
self . stripe_customer_id = customer . id
self . stored_credit_card = true
if self . save
2016-04-21 14:23:29 +00:00
if booking_id
approved_booking = LessonBooking . find_by_id ( booking_id )
if approved_booking
approved_booking . card_approved
end
2016-04-06 02:23:15 +00:00
end
2016-05-11 21:03:55 +00:00
2016-06-03 04:32:09 +00:00
if test_drive_package_choice_id
choice = TestDrivePackageChoice . find ( test_drive_package_choice_id )
choice . lesson_bookings . each do | booking |
booking . card_approved
end
end
2016-05-11 21:03:55 +00:00
if uncollectables . count > 0
found_uncollectables = uncollectables
uncollectables . update_all ( billing_should_retry : true )
else
found_uncollectables = nil
end
2016-04-06 02:23:15 +00:00
end
end
2016-06-03 04:32:09 +00:00
[ approved_booking , found_uncollectables , choice ]
2016-04-06 02:23:15 +00:00
end
def update_name ( name )
if name . blank?
self . first_name = ''
self . last_name = ''
else
bits = name . split
if bits . length == 1
self . first_name = ''
self . last_name = bits [ 0 ] . strip
elsif bits . length == 2
self . first_name = bits [ 0 ] . strip
self . last_name = bits [ 1 ] . strip
else
self . first_name = bits [ 0 ] . strip
self . last_name = bits [ 1 .. - 1 ] . join ( ' ' )
end
end
self . save
end
def payment_update ( params )
booking = nil
test_drive = nil
normal = nil
intent = nil
purchase = nil
2016-05-05 02:20:38 +00:00
lesson_package_type = nil
2016-05-11 21:03:55 +00:00
uncollectables = nil
2016-06-03 04:32:09 +00:00
choice = nil
2017-07-10 02:21:29 +00:00
posa_card = nil
2016-04-06 02:23:15 +00:00
User . transaction do
if params [ :name ] . present?
if ! self . update_name ( params [ :name ] )
return nil
end
end
2016-06-03 04:32:09 +00:00
booking , uncollectables , choice = card_approved ( params [ :token ] , params [ :zip ] , params [ :booking_id ] , params [ :test_drive_package_choice_id ] )
2016-04-06 02:23:15 +00:00
if params [ :test_drive ]
self . reload
2016-05-05 02:20:38 +00:00
if booking
2017-07-10 02:21:29 +00:00
# bookin will indicate test package
2016-05-05 02:20:38 +00:00
lesson_package_type = booking . resolved_test_drive_package
2017-07-10 02:21:29 +00:00
posa_card = booking . posa_card
2016-06-03 04:32:09 +00:00
elsif choice
2017-07-10 02:21:29 +00:00
# packages also indicate lesson package
2016-06-03 13:06:47 +00:00
lesson_package_type = choice . lesson_package_type
2017-07-10 02:21:29 +00:00
elsif self . lesson_package_needs_purchase
# user has a POSA card requiring purchase, so this takes preference over the 'desired_package' (a user could have both set, but we force user to pay for POSA_CARD requiring purchase before picking up a random TD purchase)
lesson_package_type = self . lesson_package_needs_purchase
# also update POSA cards indicating they have been bought. This below code is a little bit
posa_card = self . posa_cards . where ( requires_purchase : true ) . where ( purchased : false ) . order ( :created_at ) . first
else
# the user has at some point b4 indicated interest in a package; so in absence of above indicators, this is what they are buying
lesson_package_type = self . desired_package
2016-05-05 02:20:38 +00:00
end
2016-06-03 04:32:09 +00:00
2017-07-10 02:21:29 +00:00
result = Sale . purchase_test_drive ( self , lesson_package_type , booking , posa_card )
2016-04-06 02:23:15 +00:00
test_drive = result [ :sale ]
purchase = result [ :purchase ]
2016-05-05 02:20:38 +00:00
2017-07-10 02:21:29 +00:00
if posa_card && ! purchase . errors . any?
posa_card . has_been_purchased ( false )
end
2016-05-05 02:20:38 +00:00
if booking && ! purchase . errors . any?
# the booking would not have a lesson_package_purchase associated yet, so let's associate it
booking . lesson_sessions . update_all ( lesson_package_purchase_id : purchase . id )
end
2016-04-06 02:23:15 +00:00
elsif params [ :normal ]
self . reload
end
end
2017-07-10 02:21:29 +00:00
2016-06-03 04:32:09 +00:00
{ lesson : booking , test_drive : test_drive , purchase : purchase , lesson_package_type : lesson_package_type , uncollectables : uncollectables , package : choice }
2016-04-06 02:23:15 +00:00
end
def requested_test_drive ( teacher = nil )
query = LessonBooking . requested ( self ) . where ( lesson_type : LessonBooking :: LESSON_TYPE_TEST_DRIVE )
if teacher
query = query . where ( teacher_id : teacher . id )
end
query . first
end
def unprocessed_test_drive
LessonBooking . unprocessed ( self ) . where ( lesson_type : LessonBooking :: LESSON_TYPE_TEST_DRIVE ) . first
end
def unprocessed_normal_lesson
LessonBooking . unprocessed ( self ) . where ( lesson_type : LessonBooking :: LESSON_TYPE_PAID ) . first
end
2016-09-27 02:56:12 +00:00
def most_recent_posa_purchase
lesson_purchases . where ( 'lesson_package_type_id in (?)' , LessonPackageType . test_drive_package_ids ) . where ( 'posa_card_id is not null' ) . order ( 'created_at desc' ) . first
end
2017-07-10 02:21:29 +00:00
def most_recent_posa_card
posa_cards . where ( 'lesson_package_type_id in (?)' , LessonPackageType . test_drive_package_ids ) . order ( 'created_at desc' ) . first
end
2016-05-31 16:54:20 +00:00
def most_recent_test_drive_purchase
2016-05-20 20:33:44 +00:00
lesson_purchases . where ( 'lesson_package_type_id in (?)' , LessonPackageType . test_drive_package_ids ) . order ( 'created_at desc' ) . first
2016-04-06 02:23:15 +00:00
end
2016-05-11 02:10:24 +00:00
def total_test_drives
purchase = most_recent_test_drive_purchase
if purchase
purchase . test_drive_count
else
0
end
end
2016-09-27 02:56:12 +00:00
def total_posa_credits
purchase = most_recent_posa_purchase
if purchase
purchase . posa_card . credits
else
0
end
end
2016-04-06 02:23:15 +00:00
def test_drive_succeeded ( lesson_session )
2016-10-03 02:51:34 +00:00
if ( lesson_session . posa_card && self . jamclass_credits < = 0 ) || ( ! lesson_session . posa_card && self . remaining_test_drives < = 0 )
2016-07-17 15:16:27 +00:00
UserMailer . student_test_drive_lesson_done ( lesson_session ) . deliver_now
UserMailer . teacher_lesson_completed ( lesson_session ) . deliver_now
2016-04-06 02:23:15 +00:00
else
2016-07-17 15:16:27 +00:00
UserMailer . student_test_drive_lesson_completed ( lesson_session ) . deliver_now
UserMailer . teacher_lesson_completed ( lesson_session ) . deliver_now
2016-04-06 02:23:15 +00:00
end
end
2016-04-21 14:23:29 +00:00
def test_drive_declined ( lesson_session )
# because we decrement test_drive credits as soon as you book, we need to bring it back now
2016-05-19 18:26:37 +00:00
if lesson_session . lesson_booking . user_decremented
2016-09-27 02:56:12 +00:00
if lesson_session . posa_card
self . jamclass_credits = self . jamclass_credits + 1
else
self . remaining_test_drives = self . remaining_test_drives + 1
end
2016-04-21 14:23:29 +00:00
self . save ( validate : false )
2016-05-19 18:26:37 +00:00
end
2016-04-21 14:23:29 +00:00
end
2016-04-06 02:23:15 +00:00
def test_drive_failed ( lesson_session )
2016-05-19 18:26:37 +00:00
if lesson_session . lesson_booking . user_decremented
# because we decrement test_drive credits as soon as you book, we need to bring it back now
2016-09-27 02:56:12 +00:00
if lesson_session . posa_card
self . jamclass_credits = self . jamclass_credits + 1
else
self . remaining_test_drives = self . remaining_test_drives + 1
end
2016-05-19 18:26:37 +00:00
self . save ( validate : false )
end
2016-07-17 15:16:27 +00:00
UserMailer . teacher_test_drive_no_bill ( lesson_session ) . deliver_now
UserMailer . student_test_drive_no_bill ( lesson_session ) . deliver_now
2016-04-06 02:23:15 +00:00
end
def used_test_drives
2016-05-11 02:10:24 +00:00
total_test_drives - remaining_test_drives
2016-04-06 02:23:15 +00:00
end
2016-09-27 02:56:12 +00:00
def used_posa_credits
total_posa_credits - jamclass_credits
end
2016-05-11 21:03:55 +00:00
def uncollectables ( limit = 10 )
LessonPaymentCharge . where ( user_id : self . id ) . order ( :created_at ) . where ( 'billing_attempts > 0' ) . where ( billed : false ) . limit ( limit )
end
2016-04-06 02:23:15 +00:00
def has_rated_teacher ( teacher )
2016-05-18 01:29:56 +00:00
teacher_rating ( teacher ) . count > 0
2016-05-16 16:39:20 +00:00
end
2016-05-17 18:31:53 +00:00
def teacher_rating ( teacher )
if teacher . is_a? ( JamRuby :: User )
teacher = teacher . teacher
end
Review . where ( target_id : teacher . id ) . where ( target_type : teacher . class . to_s )
2016-04-06 02:23:15 +00:00
end
def has_rated_student ( student )
2016-05-18 01:29:56 +00:00
student_rating ( student ) . count > 0
end
def student_rating ( student )
Review . where ( target_id : student . id ) . where ( target_type : " JamRuby::User " )
2016-04-06 02:23:15 +00:00
end
def teacher_profile_url
" #{ APP_CONFIG . external_root_url } /client # /profile/teacher/ #{ id } "
end
2016-05-18 01:29:56 +00:00
def profile_url
" #{ APP_CONFIG . external_root_url } /client # /profile/ #{ id } "
end
2016-04-06 02:23:15 +00:00
def ratings_url
2016-05-17 18:31:53 +00:00
" #{ APP_CONFIG . external_root_url } /client?tile=ratings # /profile/teacher/ #{ id } "
2016-04-06 02:23:15 +00:00
end
def student_ratings_url
" #{ APP_CONFIG . external_root_url } /client?selected=ratings # /profile/ #{ id } "
end
def self . search_url
" #{ APP_CONFIG . external_root_url } /client # /jamclass/searchOptions "
end
def recent_test_drive_teachers
2016-08-03 01:46:15 +00:00
User . select ( 'distinct on (users.id) users.*' ) . joins ( taught_lessons : :music_session ) . where ( 'lesson_sessions.lesson_type = ?' , LessonSession :: LESSON_TYPE_TEST_DRIVE ) . where ( 'music_sessions.user_id = ?' , id ) . where ( 'lesson_sessions.created_at > ?' , APP_CONFIG . test_drive_wait_period_year . years . ago )
2016-04-06 02:23:15 +00:00
end
2016-03-21 21:37:13 +00:00
def mark_session_ready
self . ready_for_session_at = Time . now
self . save!
end
2018-01-17 04:01:07 +00:00
def mark_session_not_ready
self . ready_for_session_at = nil
self . save!
end
2018-02-25 22:28:12 +00:00
def mark_sent_paid_lesson
self . stuck_take_plesson = false
self . sent_admin_take_plesson_email_at = Time . now
self . save!
end
def mark_sent_2nd_free_lesson
self . stuck_take_2nd_flesson = false
self . sent_admin_take_2nd_flesson_email_at = Time . now
self . save!
end
def mark_sent_1st_free_lesson
self . stuck_take_flesson = false
self . sent_admin_take_flesson_email_at = Time . now
self . save!
end
def mark_onboarded
self . onboarding_onboarded_at = Time . now
self . save!
end
2018-02-25 22:49:04 +00:00
def mark_lost ( lost_reason = LOST_REASON_OTHER )
self . onboarding_lost_at = Time . now
self . onboarding_lost_reason = lost_reason
self . save!
end
2016-04-06 02:23:15 +00:00
def has_booked_with_student? ( student , since_at = nil )
LessonBooking . engaged_bookings ( student , self , since_at ) . count > 0
end
def has_booked_test_drive_with_student? ( student , since_at = nil )
LessonBooking . engaged_bookings ( student , self , since_at ) . test_drive . count > 0
end
2016-09-08 10:59:58 +00:00
def same_school_with_student? ( student )
student . school && self . teacher && self . teacher . school && student . school . id == self . teacher . school . id
end
2018-01-23 03:50:45 +00:00
def computed_onboarding_status
if first_onboarding_paid_lesson_at
ONBOARDING_STATUS_PAID_LESSON
2018-02-25 22:28:12 +00:00
elsif second_onboarding_free_lesson_at || first_onboarding_free_lesson_at
2018-01-23 03:50:45 +00:00
ONBOARDING_STATUS_FREE_LESSON
elsif onboarding_onboarded_at
ONBOARDING_STATUS_ONBOARDED
elsif onboarding_lost_reason
ONBOARDING_STATUS_LOST
elsif onboarding_escalation_reason
ONBOARDING_STATUS_ESCALATED
elsif onboarding_email_5_sent_at
ONBOARDING_STATUS_EMAILED
elsif onboarder_id
ONBOARDING_STATUS_ASSIGNED
else
ONBOARDING_STATUS_UNASSIGNED
end
end
2013-03-15 04:22:31 +00:00
private
2016-01-04 19:42:11 +00:00
def create_remember_token
self . remember_token = SecureRandom . urlsafe_base64
end
2013-05-31 01:59:37 +00:00
2015-10-16 19:01:18 +00:00
def default_anonymous_names
self . first_name = 'Anonymous' if self . first_name . nil?
self . last_name = 'Anonymous' if self . last_name . nil?
end
2016-01-04 19:42:11 +00:00
def stringify_avatar_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 = original_fpfile . to_json if ! original_fpfile . nil?
self . cropped_fpfile = cropped_fpfile . to_json if ! cropped_fpfile . nil?
self . crop_selection = crop_selection . to_json if ! crop_selection . nil?
end
2012-08-06 03:01:00 +00:00
end
2012-08-22 03:07:01 +00:00
end