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
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
2014-05-17 19:55:26 +00:00
# after_save :check_lat_lng
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
2014-04-30 03:01:28 +00:00
attr_accessor :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
2012-11-07 13:10:41 +00:00
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'
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
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
2012-11-21 19:48:39 +00:00
has_many :musician_instruments , :class_name = > " JamRuby::MusicianInstrument "
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 "
2012-10-14 02:18:20 +00:00
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
2012-11-16 02:08:37 +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
2013-03-31 18:07:46 +00:00
# notifications
has_many :notifications , :class_name = > " JamRuby::Notification " , :foreign_key = > " target_user_id "
has_many :inverse_notifications , :through = > :notifications , :class_name = > " JamRuby::User "
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
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 "
2014-04-20 22:54:49 +00:00
# affiliate_partner
has_one :affiliate_partner , :class_name = > " JamRuby::AffiliatePartner " , :foreign_key = > :partner_user_id
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
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'
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
2012-12-09 04:05:54 +00:00
before_save :create_remember_token , :if = > :should_validate_password?
2013-05-31 01:59:37 +00:00
before_save :stringify_avatar_info , :if = > :updating_avatar
2012-11-03 15:38:00 +00:00
2013-07-26 08:07:24 +00:00
validates :first_name , presence : true , length : { maximum : 50 } , no_profanity : true
validates :last_name , presence : true , 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
2013-03-15 04:22:31 +00:00
validates :terms_of_service , :acceptance = > { :accept = > true , :on = > :create , :allow_nil = > false }
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 ] }
2014-04-30 03:01:28 +00:00
validates :mods , json : true
2014-06-09 20:43:16 +00:00
validates_numericality_of :last_jam_audio_latency , greater_than : 0 , :allow_nil = > true
2014-07-22 19:36:45 +00:00
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
2013-07-10 20:18:25 +00:00
# custom validators
2013-03-15 04:22:31 +00:00
validate :validate_musician_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
2013-05-31 01:59:37 +00:00
2013-11-23 07:44:13 +00:00
scope :musicians , where ( :musician = > true )
2014-01-11 12:26:40 +00:00
scope :fans , where ( :musician = > false )
2014-05-29 02:19:50 +00:00
scope :geocoded_users , where ( User . arel_table [ :last_jam_locidispid ] . not_eq ( nil ) )
2014-05-26 19:16:01 +00:00
scope :musicians_geocoded , musicians . geocoded_users
2014-04-01 14:42:26 +00:00
scope :email_opt_in , where ( :subscribe_email = > true )
2013-11-23 07:44:13 +00:00
2013-09-30 02:37:22 +00:00
def user_progression_fields
2014-01-30 21:51:05 +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 " ]
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
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
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
2012-11-09 06:29:05 +00:00
@online || = ! self . connections . nil? && self . connections . size > 0
2012-10-14 02:18:20 +00:00
end
2012-11-18 02:59:59 +00:00
def name
2014-02-13 16:41:50 +00:00
" #{ first_name } #{ last_name } "
2012-11-18 02:59:59 +00:00
end
2012-11-07 13:10:41 +00:00
def location
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?
2013-03-03 00:40:58 +00:00
#loc = loc.blank? ? self.country : "#{loc}, #{self.country}" unless self.country.blank?
2014-07-20 02:11:16 +00:00
# XXX WHY IS COUNTRY COMMENTED OUT?
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 )
2014-02-16 01:24:51 +00:00
self . friends . exists? ( user )
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
def session_count
2014-02-16 01:24:51 +00:00
self . music_sessions . 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
MusicSession . scheduled_rsvp ( self , true ) . length
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-08-18 15:37:55 +00:00
# ===== ARTIFICIAL ATTRIBUTES CREATED BY ActiveMusicSession.ams_users, MusicSession.sms_uses
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
# ====== END ARTIFICAL ATTRIBUTES
2014-04-30 03:01:28 +00:00
# mods comes back as text; so give ourselves a parsed version
def mods_json
@mods_json || = mods ? JSON . parse ( mods , symbolize_names : true ) : { }
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-01-21 06:45:51 +00:00
def recent_history
2014-09-12 01:52:26 +00:00
recordings = Recording
. joins ( :claimed_recordings )
. where ( :owner_id = > self . id )
2014-01-26 21:46:41 +00:00
. order ( 'created_at DESC' )
. limit ( 10 )
2014-05-06 13:34:38 +00:00
msh = MusicSession . where ( :user_id = > self . id )
2014-01-26 21:46:41 +00:00
. order ( 'created_at DESC' )
. limit ( 10 )
2014-01-21 06:45:51 +00:00
recordings . concat ( msh )
recordings . sort! { | a , b | b . created_at < = > a . created_at } . first ( 5 )
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
end
def my_session_settings
unless self . session_settings . nil?
return JSON . parse ( self . session_settings )
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
if ! first_name . nil? && ! last_name . nil?
return first_name + ' ' + last_name
end
2014-04-30 03:01:28 +00:00
id
2012-08-29 13:21:30 +00:00
end
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
attributes = { :password = > new_password , :password_confirmation = > new_password_confirmation }
# taken liberally from Devise::DatabaseAuthenticatable.update_with_password
if valid_password? ( old_password )
update_attributes ( attributes )
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
def change_password ( new_password , new_password_confirmation )
2012-12-14 03:32:23 +00:00
# FIXME: Should verify that the new password meets certain quality criteria. Really, maybe that should be a
# verification step.
2012-12-22 00:56:16 +00:00
self . updating_password = true
2012-12-14 03:32:23 +00:00
self . password = new_password
self . password_confirmation = new_password_confirmation
2012-12-14 09:16:54 +00:00
UserMailer . password_changed ( self ) . deliver
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 ) } "
UserMailer . password_reset ( user , reset_url ) . deliver
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 )
. where ( :musicians_recordings = > { :user_id = > " #{ user_id } " } , :public = > true )
else
recordings = Recording . joins ( :musician_recordings )
. where ( :musicians_recordings = > { :user_id = > " #{ user_id } " } )
end
return recordings
end
2012-12-13 17:15:47 +00:00
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?
MusicianInstrument . delete_all ( [ " user_id = ? " , self . id ] )
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
musician_instrument . user = self
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 ,
2013-11-03 03:35:18 +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 ,
2013-11-03 03:35:18 +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
raise PermissionError , ValidationMessages :: PERMISSION_VALIDATION_ERROR
end
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)
# 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
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
0 # FIXME: update this with recording likes count when implemented
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
2014-05-06 21:17:26 +00:00
session_settings = { :band_id = > music_session . band_id ,
2012-12-09 04:05:54 +00:00
: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 ,
2012-12-10 05:53:21 +00:00
:genres = > genres ,
:invitees = > invitees
2012-12-09 04:05:54 +00:00
} . to_json
user . session_settings = session_settings
user . save
end
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 ]
2014-02-03 21:19:14 +00:00
2012-11-21 19:48:39 +00:00
user = User . new
2012-11-07 13:10:41 +00:00
2012-11-21 19:48:39 +00:00
UserManager . active_record_transaction do | user_manager |
user . first_name = first_name
user . last_name = last_name
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
2013-06-22 02:28:42 +00:00
user . musician = musician
2012-11-21 19:48:39 +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?
2013-03-15 04:22:31 +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
musician_instrument . user = user
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
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
2012-11-21 19:48:39 +00:00
user . save
2012-11-15 09:30:55 +00:00
2012-11-21 19:48:39 +00:00
if user . errors . any?
raise ActiveRecord :: Rollback
else
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?
2014-02-03 21:19:14 +00:00
# don't send an signup email if email is already confirmed
if user . email_confirmed
2013-09-26 13:43:02 +00:00
UserMailer . welcome_message ( user ) . deliver
2013-03-15 04:22:31 +00:00
else
# 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
2013-09-26 13:43:02 +00:00
UserMailer . confirm_email ( user , signup_confirm_url . nil? ? nil : ( signup_confirm_url + " / " + user . signup_token ) ) . deliver
2013-03-15 04:22:31 +00:00
end
2012-11-14 05:37:18 +00:00
end
end
2012-11-21 19:48:39 +00:00
return user
end
2012-11-14 05:37:18 +00:00
2012-12-09 20:56:35 +00:00
# this is intended to be development-mode or test-mode only; VRFS-149
# it creates or updates one user per developer, so that we aren't in the business
# of constantly recreating users as we create new dev environments
# 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
user = User . find_or_create_by_email ( email )
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?
MusicianInstrument . delete_all ( [ " user_id = ? " , user . id ] )
end
instruments . each do | musician_instrument_param |
instrument = Instrument . find ( musician_instrument_param [ :instrument_id ] )
musician_instrument = MusicianInstrument . new
musician_instrument . user = user
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
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
# 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
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 (
2013-05-31 01:59:37 +00:00
:original_fpfile = > original_fpfile ,
:cropped_fpfile = > cropped_fpfile ,
2014-02-06 16:31:52 +00:00
:cropped_large_fpfile = > cropped_large_fpfile ,
2013-05-31 01:59:37 +00:00
:cropped_s3_path = > cropped_s3_path ,
2014-02-06 16:31:52 +00:00
:cropped_large_s3_path = > cropped_large_s3_path ,
2013-05-31 01:59:37 +00:00
:crop_selection = > crop_selection ,
2014-02-07 23:56:39 +00:00
:photo_url = > S3Util . url ( aws_bucket , escape_filename ( cropped_s3_path ) , :secure = > false ) ,
:large_photo_url = > S3Util . url ( aws_bucket , escape_filename ( cropped_large_s3_path ) , :secure = > false )
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
2012-11-21 19:48:39 +00:00
UserManager . active_record_transaction do | user_manager |
# 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' ,
2014-02-07 14:07:08 +00:00
uid : twitter_uid ,
token : token ,
2014-02-07 17:18:57 +00:00
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
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 )
2014-08-18 15:37:55 +00:00
if audio_latency > 2
# updating the connection is best effort
if connection
connection . last_jam_audio_latency = audio_latency
connection . save
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 } ' " )
. where ( [ 'follows.user_id = ?' , self . id ] )
2013-11-15 19:52:06 +00:00
. order ( 'follows.created_at DESC' )
. limit ( 3 )
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 |
UserMailer . new_musicians ( usr , new_nearby ) . deliver
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
2013-03-15 04:22:31 +00:00
# end devise compatibility
private
def create_remember_token
self . remember_token = SecureRandom . urlsafe_base64
2012-11-25 19:37:54 +00:00
end
2013-05-31 01:59:37 +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