1147 lines
41 KiB
Ruby
1147 lines
41 KiB
Ruby
require 'sanitize'
|
|
class ApiUsersController < ApiController
|
|
|
|
before_filter :api_signed_in_user, :except => [:create, :calendar, :show, :signup_confirm, :auth_session_create, :complete, :finalize_update_email, :isp_scoring, :add_play, :crash_dump, :validate_data, :google_auth, :user_event]
|
|
before_filter :auth_user, :only => [:session_settings_show, :session_history_index, :session_user_history_index, :update, :delete, :authorizations, :test_drive_status,
|
|
:liking_create, :liking_destroy, # likes
|
|
:following_create, :following_show, :following_destroy, # followings
|
|
:recording_update, :recording_destroy, # recordings
|
|
:favorite_create, :favorite_destroy, # favorites
|
|
:friend_request_index, :friend_request_show, :friend_request_create, :friend_request_update, # friend requests
|
|
:friend_show, :friend_destroy, # friends
|
|
:notification_index, :notification_destroy, # notifications
|
|
:band_invitation_index, :band_invitation_show, :band_invitation_update, # band invitations
|
|
:set_password, :begin_update_email, :update_avatar, :delete_avatar, :generate_filepicker_policy,
|
|
:share_session, :share_recording,
|
|
:affiliate_report, :audio_latency, :broadcast_notification, :redeem_giftcard]
|
|
before_filter :ip_blacklist, :only => [:create, :redeem_giftcard]
|
|
|
|
respond_to :json, :except => :calendar
|
|
respond_to :ics, :only => :calendar
|
|
|
|
def index
|
|
@users = User.paginate(page: params[:page])
|
|
respond_with @users, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def calendar
|
|
#@user=lookup_user
|
|
#ics = CalendarManager.new.create_ics_feed(@user)
|
|
#send_data ics, :filename => 'JamKazam', :disposition => 'inline', :type => "text/calendar"
|
|
render :json => {}, :status => 200
|
|
end
|
|
|
|
def show
|
|
@user=lookup_user
|
|
|
|
@show_teacher = true
|
|
@show_profile = params[:show_profile]
|
|
@show_student = params[:show_student]
|
|
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def authorizations
|
|
|
|
@user = current_user
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def jamblasters
|
|
@user = current_user
|
|
@connection = Connection.find_by_client_id(params[:client_id])
|
|
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def google_auth
|
|
@user = current_user
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def profile_show
|
|
@profile = User.includes([{musician_instruments: :instrument},
|
|
{band_musicians: :user},
|
|
{genre_players: :genre},
|
|
:bands, :instruments, :genres,
|
|
:online_presences, :performance_samples])
|
|
.find(params[:id])
|
|
|
|
@show_teacher_profile = params[:show_teacher]
|
|
|
|
respond_with @profile, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
# in other words, a minimal signup
|
|
def create
|
|
# today, this only accepts a minimal registration; it could be made to take in more if we wanted
|
|
signup_hint = nil
|
|
if anonymous_user
|
|
signup_hint = anonymous_user.signup_hint
|
|
if signup_hint && signup_hint.jam_track.nil?
|
|
signup_hint = nil # it doesn't make sense to pass in signup hints that are not free jam-track centric (at least, not today)
|
|
end
|
|
end
|
|
|
|
# recaptcha_response: params['g-recaptcha-response']
|
|
|
|
# try to autologin , because users will try to log in via signup link
|
|
if(params[:email] && params[:password])
|
|
test = User.authenticate(params[:email], params[:password])
|
|
if test
|
|
@user = test
|
|
@autologin = true
|
|
@user.school_interest = !!params[:school_interest]
|
|
@user.education_interest = !!params[:education_interest]
|
|
@user.retailer_interest = !!params[:retailer_interest]
|
|
@user.save
|
|
sign_in @user
|
|
new_user(@user, signup_hint) # sets a cookie used for GA analytics (one-time new user stuff in JavaScript)
|
|
respond_with_model(@user, new: true, location: lambda { return api_user_detail_url(@user.id) })
|
|
return
|
|
end
|
|
end
|
|
|
|
|
|
options = {
|
|
first_name: params[:first_name],
|
|
last_name: params[:last_name],
|
|
email: params[:email],
|
|
password: params[:password],
|
|
password_confirmation: params[:password],
|
|
terms_of_service: params[:terms],
|
|
location: {:country => nil, :state => nil, :city => nil},
|
|
signup_hint: signup_hint,
|
|
gift_card: params[:gift_card],
|
|
student: params[:student],
|
|
teacher: params[:teacher],
|
|
school_invitation_code: params[:school_invitation_code],
|
|
school_id: params[:school_id],
|
|
retailer_invitation_code: params[:retailer_invitation_code],
|
|
retailer_id: params[:retailer_id],
|
|
school_interest: params[:school_interest],
|
|
retailer_interest: params[:retailer_interest],
|
|
education_interest: params[:education_interest],
|
|
affiliate_referral_id: cookies[:affiliate_visitor],
|
|
origin: origin_cookie,
|
|
test_drive_package: params[:test_drive_package]
|
|
}
|
|
|
|
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)
|
|
|
|
@user = UserManager.new.signup(options)
|
|
|
|
if @user.errors.any?
|
|
respond_with_model(@user)
|
|
else
|
|
sign_in @user
|
|
new_user(@user, signup_hint) # sets a cookie used for GA analytics (one-time new user stuff in JavaScript)
|
|
respond_with_model(@user, new: true, location: lambda { return api_user_detail_url(@user.id) })
|
|
end
|
|
end
|
|
|
|
def profile_save
|
|
end
|
|
|
|
def update
|
|
|
|
@user = User.find(params[:id])
|
|
@user.first_name = params[:first_name] if params.has_key?(:first_name)
|
|
@user.last_name = params[:last_name] if params.has_key?(:last_name)
|
|
@user.gender = params[:gender] if params.has_key?(:gender)
|
|
@user.birth_date = Date.strptime(params[:birth_date], '%m-%d-%Y') if (params.has_key?(:birth_date) && params[:birth_date])
|
|
@user.city = params[:city] if params.has_key?(:city)
|
|
@user.state = params[:state] if params.has_key?(:state)
|
|
@user.country = params[:country] if params.has_key?(:country)
|
|
@user.musician = params[:musician] if params.has_key?(:musician)
|
|
@user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments)
|
|
|
|
# genres
|
|
@user.update_genres(params[:genres].nil? ? [] : params[:genres], GenrePlayer::PROFILE) if params.has_key?(:genres)
|
|
@user.update_genres(params[:virtual_band_genres].nil? ? [] : params[:virtual_band_genres], GenrePlayer::VIRTUAL_BAND) if params.has_key?(:virtual_band_genres)
|
|
@user.update_genres(params[:traditional_band_genres].nil? ? [] : params[:traditional_band_genres], GenrePlayer::TRADITIONAL_BAND) if params.has_key?(:traditional_band_genres)
|
|
@user.update_genres(params[:paid_session_genres].nil? ? [] : params[:paid_session_genres], GenrePlayer::PAID_SESSION) if params.has_key?(:paid_session_genres)
|
|
@user.update_genres(params[:free_session_genres].nil? ? [] : params[:free_session_genres], GenrePlayer::FREE_SESSION) if params.has_key?(:free_session_genres)
|
|
@user.update_genres(params[:cowriting_genres].nil? ? [] : params[:cowriting_genres], GenrePlayer::COWRITING) if params.has_key?(:cowriting_genres)
|
|
|
|
@user.show_whats_next = params[:show_whats_next] if params.has_key?(:show_whats_next)
|
|
@user.show_whats_next_count = params[:show_whats_next_count] if params.has_key?(:show_whats_next_count)
|
|
@user.subscribe_email = params[:subscribe_email] if params.has_key?(:subscribe_email)
|
|
@user.biography = params[:biography] if params.has_key?(:biography)
|
|
|
|
@user.website = params[:website] if params.has_key?(:website)
|
|
@user.skill_level = params[:skill_level] if params.has_key?(:skill_level)
|
|
@user.concert_count = params[:concert_count] if params.has_key?(:concert_count)
|
|
@user.studio_session_count = params[:studio_session_count] if params.has_key?(:studio_session_count)
|
|
|
|
# virtual band
|
|
@user.virtual_band = params[:virtual_band] if params.has_key?(:virtual_band)
|
|
@user.virtual_band_commitment = params[:virtual_band_commitment] if params.has_key?(:virtual_band_commitment)
|
|
|
|
# traditional band
|
|
@user.traditional_band = params[:traditional_band] if params.has_key?(:traditional_band)
|
|
@user.traditional_band_commitment = params[:traditional_band_commitment] if params.has_key?(:traditional_band_commitment)
|
|
@user.traditional_band_touring = params[:traditional_band_touring] if params.has_key?(:traditional_band_touring)
|
|
|
|
# paid sessions
|
|
@user.paid_sessions = params[:paid_sessions] if params.has_key?(:paid_sessions)
|
|
@user.paid_sessions_hourly_rate = params[:paid_sessions_hourly_rate] if params.has_key?(:paid_sessions_hourly_rate)
|
|
@user.paid_sessions_daily_rate = params[:paid_sessions_daily_rate] if params.has_key?(:paid_sessions_daily_rate)
|
|
|
|
# free sessions
|
|
@user.free_sessions = params[:free_sessions] if params.has_key?(:free_sessions)
|
|
|
|
# co-writing
|
|
@user.cowriting = params[:cowriting] if params.has_key?(:cowriting)
|
|
@user.cowriting_purpose = params[:cowriting_purpose] if params.has_key?(:cowriting_purpose)
|
|
|
|
@user.want_jamblaster = params[:want_jamblaster] if params.has_key?(:want_jamblaster)
|
|
@user.mod_merge(params[:mods]) if params[:mods]
|
|
|
|
# allow keyword of 'LATEST' to mean set the notification_seen_at to the most recent notification for this user
|
|
if params.has_key?(:notification_seen_at)
|
|
@user.update_notification_seen_at params[:notification_seen_at]
|
|
end
|
|
|
|
@user.update_online_presences(params[:online_presences]) if params.has_key?(:online_presences)
|
|
@user.update_performance_samples(params[:performance_samples]) if params.has_key?(:performance_samples)
|
|
@user.update_calendars(params[:calendars]) if params.has_key?(:calendars)
|
|
@user.is_a_student = params[:student] if params.has_key?(:student)
|
|
@user.is_a_teacher = params[:teacher] if params.has_key?(:teacher)
|
|
@user.school_interest = !!params[:school_interest]
|
|
@user.education_interest = !!params[:education_interest]
|
|
@user.retailer_interest = !!params[:retailer_interest]
|
|
@user.desired_package = LessonPackageType.find_by_package_type!(params[:desired_package]) if params.has_key?(:desired_package)
|
|
if @user.save
|
|
|
|
test_drive_package_details = params[:test_drive_package]
|
|
test_drive_package = TestDrivePackage.find_by_name(test_drive_package_details[:name]) if test_drive_package_details
|
|
@user.handle_test_drive_package(test_drive_package, test_drive_package_details) if test_drive_package
|
|
end
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, :status => :unprocessable_entity
|
|
else
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
end
|
|
|
|
# a user that is created administratively has an incomplete profile
|
|
# when they first visit the confirmation page by clicking the link in their email.
|
|
def complete
|
|
|
|
signup_token = params[:signup_token]
|
|
user = User.find_by_signup_token(signup_token)
|
|
|
|
if user.nil?
|
|
return
|
|
end
|
|
|
|
user.updating_password = true
|
|
|
|
user.easy_save(
|
|
params[:first_name],
|
|
params[:last_name],
|
|
nil, # email can't be edited at this phase. We need to get them into the site, and they can edit on profile page if they really want
|
|
params[:password],
|
|
params[:password_confirmation],
|
|
true, # musician
|
|
params[:gender],
|
|
params[:birth_date],
|
|
params[:isp],
|
|
params[:city],
|
|
params[:state],
|
|
params[:country],
|
|
params[:instruments],
|
|
params[:photo_url])
|
|
|
|
if user.errors.any?
|
|
render :json => user.errors.full_messages(), :status => :unprocessable_entity
|
|
else
|
|
# log the user in automatically
|
|
user.signup_confirm
|
|
sign_in(user)
|
|
respond_with user, responder: ApiResponder, :status => 200
|
|
end
|
|
end
|
|
|
|
def delete
|
|
@user.destroy
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
def signup_confirm
|
|
@user = UserManager.new.signup_confirm(params[:signup_token])
|
|
|
|
unless @user.errors.any?
|
|
respond_with @user, responder: ApiResponder, :location => api_user_detail_url(@user)
|
|
else
|
|
response.status = :unprocessable_entity
|
|
respond_with @user, responder: ApiResponder
|
|
end
|
|
end
|
|
|
|
def set_password
|
|
|
|
@user.set_password(params[:old_password], params[:new_password], params[:new_password_confirm])
|
|
|
|
if @user.errors.any?
|
|
response.status = :unprocessable_entity
|
|
respond_with @user
|
|
else
|
|
sign_in(@user)
|
|
respond_with @user, responder: ApiResponder, status: 200
|
|
end
|
|
end
|
|
|
|
def reset_password
|
|
begin
|
|
User.reset_password(params[:email], ApplicationHelper.base_uri(request))
|
|
rescue JamRuby::JamArgumentError
|
|
render :json => {:message => ValidationMessages::EMAIL_NOT_FOUND}, :status => 403
|
|
end
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
def reset_password_token
|
|
begin
|
|
User.set_password_from_token(params[:email], params[:token], params[:new_password], params[:new_password_confirm])
|
|
rescue JamRuby::JamArgumentError
|
|
# FIXME
|
|
# There are some other errors that can happen here, besides just EMAIL_NOT_FOUND
|
|
render :json => {:message => ValidationMessages::EMAIL_NOT_FOUND}, :status => 403
|
|
end
|
|
set_remember_token(@user)
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
###################### AUTHENTICATION ###################
|
|
def auth_session_create
|
|
@user = User.authenticate(params[:email], params[:password])
|
|
|
|
if @user.nil?
|
|
render :json => {:success => false}, :status => 404
|
|
else
|
|
sign_in @user
|
|
render :json => {:success => true}, :status => 200
|
|
end
|
|
end
|
|
|
|
def auth_session_delete
|
|
sign_out
|
|
render :json => {:success => true}, :status => 200
|
|
end
|
|
|
|
###################### SESSION SETTINGS ###################
|
|
def session_settings_show
|
|
respond_with :json => @user.my_session_settings.to_json, responder: ApiResponder
|
|
end
|
|
|
|
###################### SESSION HISTORY ###################
|
|
def session_history_index
|
|
@session_history = @user.session_history(params[:id], params[:band_id], params[:genre])
|
|
end
|
|
|
|
def session_user_history_index
|
|
@session_user_history = @user.session_user_history(params[:id], params[:session_id])
|
|
end
|
|
|
|
###################### BANDS ########################
|
|
def band_index
|
|
@bands = User.band_index(params[:id])
|
|
end
|
|
|
|
###################### LIKERS ########################
|
|
def liker_index
|
|
# NOTE: liker_index.rabl template references the likers property
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
###################### LIKES #########################
|
|
def liking_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def liking_create
|
|
@user = User.find(params[:id])
|
|
if !params[:user_id].nil?
|
|
@user.create_user_liking(params[:user_id])
|
|
|
|
elsif !params[:band_id].nil?
|
|
@user.create_band_liking(params[:band_id])
|
|
end
|
|
|
|
respond_with @user, responder: ApiResponder, :location => api_user_liking_index_url(@user)
|
|
end
|
|
|
|
def liking_destroy
|
|
User.delete_liking(params[:id], params[:likable_id])
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
###################### FOLLOWERS ########################
|
|
def follower_index
|
|
# NOTE: follower_index.rabl template references the followers property
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
###################### FOLLOWINGS #######################
|
|
def following_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def following_create
|
|
@user = User.find(params[:id])
|
|
if !params[:user_id].nil?
|
|
@user.create_user_following(params[:user_id])
|
|
|
|
elsif !params[:band_id].nil?
|
|
@user.create_band_following(params[:band_id])
|
|
end
|
|
|
|
respond_with @user, responder: ApiResponder, :location => api_user_following_index_url(@user)
|
|
end
|
|
|
|
def following_destroy
|
|
User.delete_following(params[:id], params[:followable_id])
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
###################### FAVORITES ########################
|
|
def favorite_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def favorite_create
|
|
@favorite = UserFavorite.new()
|
|
User.create_favorite(params[:id], params[:recording_id])
|
|
|
|
@user = User.find(params[:id])
|
|
respond_with @user, responder: ApiResponder, :location => api_favorite_index_url(@user)
|
|
end
|
|
|
|
def favorite_destroy
|
|
User.delete_favorite(params[:id], params[:recording_id])
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
###################### FRIENDS ##########################
|
|
def friend_request_index
|
|
# get all outgoing and incoming friend requests
|
|
@friend_requests = FriendRequest.where("(friend_id='#{params[:id]}' AND status is null) OR user_id='#{params[:id]}'")
|
|
end
|
|
|
|
def friend_request_show
|
|
@friend_request = FriendRequest.find(params[:friend_request_id])
|
|
raise JamRuby::JamPermissionError, 'not allowed to view someone else\'s friend request' if @friend_request.friend_id != @user.id && @friend_request.user_id != @user.id
|
|
|
|
respond_with @friend_request, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def friend_request_create
|
|
@friend_request = FriendRequest.save(nil,
|
|
params[:id],
|
|
params[:friend_id],
|
|
nil,
|
|
params[:message])
|
|
|
|
respond_with @friend_request, responder: ApiResponder, :status => 201, :location => api_friend_request_detail_url(@user, @friend_request)
|
|
end
|
|
|
|
def friend_request_update
|
|
@friend_request = FriendRequest.save(params[:friend_request_id],
|
|
params[:id],
|
|
params[:friend_id],
|
|
params[:status],
|
|
nil)
|
|
respond_with @friend_request, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def friend_index
|
|
# NOTE: friend_index.rabl template references the friends property
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def friend_show
|
|
@friend = Friendship.find_by_user_id_and_friend_id(params[:id], params[:friend_id])
|
|
end
|
|
|
|
def friend_destroy
|
|
if current_user.id != params[:id] && current_user.id != params[:friend_id]
|
|
render :json => {:message => "You are not allowed to delete this friendship."}, :status => 403
|
|
end
|
|
# clean up both records representing this "friendship"
|
|
JamRuby::Friendship.delete_all "(user_id = '#{params[:id]}' AND friend_id = '#{params[:friend_id]}') OR (user_id = '#{params[:friend_id]}' AND friend_id = '#{params[:id]}')"
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
###################### NOTIFICATIONS ####################
|
|
def notification_index
|
|
if params[:type] == 'TEXT_MESSAGE'
|
|
# you can ask for just text_message notifications
|
|
|
|
raise JamArgumentError.new('can\'t be blank', 'receiver') if params[:receiver].blank?
|
|
raise JamArgumentError.new('can\'t be blank', 'limit') if params[:limit].blank?
|
|
raise JamArgumentError.new('can\'t be blank', 'offset') if params[:offset].blank?
|
|
|
|
receiver_id = params[:receiver]
|
|
limit = params[:limit].to_i
|
|
limit = 20 if limit <= 0
|
|
offset = params[:offset].to_i
|
|
offset = 0 if offset < 0
|
|
@notifications = Notification.where(description: 'TEXT_MESSAGE').where('(source_user_id = (?) AND target_user_id = (?)) OR (source_user_id = (?) AND target_user_id = (?))', @user.id, receiver_id, receiver_id, @user.id).offset(offset).limit(limit).order('created_at DESC')
|
|
else
|
|
limit = params[:limit].to_i
|
|
limit = 20 if limit <= 0
|
|
offset = params[:offset].to_i
|
|
offset = 0 if offset < 0
|
|
@notifications = @user.notifications.offset(offset).limit(limit)
|
|
end
|
|
|
|
respond_with @notifications, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def notification_destroy
|
|
Notification.delete(params[:notification_id])
|
|
respond_with responder: ApiResponder, :status => 204
|
|
end
|
|
|
|
def notification_create
|
|
@notification = Notification.send_text_message(Sanitize.fragment(params[:message], elements: HtmlSanitize::SAFE), current_user, User.find_by_id(params[:receiver]))
|
|
respond_with_model(@notification, new: true)
|
|
end
|
|
|
|
|
|
##################### BAND INVITATIONS ##################
|
|
def band_invitation_index
|
|
@invitations = @user.received_band_invitations
|
|
respond_with @invitations, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def band_invitation_show
|
|
begin
|
|
@invitation = BandInvitation.find(params[:invitation_id])
|
|
respond_with @invitation, responder: ApiResponder, :status => 200
|
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :json => {:message => ValidationMessages::BAND_INVITATION_NOT_FOUND}, :status => 404
|
|
end
|
|
end
|
|
|
|
def band_invitation_update
|
|
begin
|
|
@invitation = BandInvitation.save(params[:invitation_id],
|
|
nil,
|
|
nil,
|
|
nil,
|
|
params[:accepted])
|
|
|
|
respond_with @invitation, responder: ApiResponder, :status => 200
|
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :json => {:message => ValidationMessages::BAND_INVITATION_NOT_FOUND}, :status => 404
|
|
end
|
|
end
|
|
|
|
###################### ACCOUNT SETTINGS #################
|
|
def begin_update_email
|
|
# begins email update by sending an email for the user to confirm their new email
|
|
|
|
# NOTE: if you change confirm_email_link value below, you break outstanding email changes because links in user inboxes are broken
|
|
confirm_email_link = confirm_email_url + "?token="
|
|
|
|
current_user.begin_update_email(params[:update_email], params[:current_password], confirm_email_link)
|
|
|
|
if current_user.errors.any?
|
|
respond_with current_user, status: :unprocessable_entity
|
|
else
|
|
respond_with current_user, responder: ApiResponder, status: 200
|
|
end
|
|
end
|
|
|
|
def finalize_update_email
|
|
# used when the user goes to the confirmation link in their email
|
|
@user = User.finalize_update_email(params[:token])
|
|
|
|
sign_in(@user)
|
|
|
|
respond_with current_user, responder: ApiResponder, status: 200
|
|
end
|
|
|
|
def isp_scoring
|
|
data = request.body.read
|
|
score = IspScoreBatch.new
|
|
score.json_scoring_data = data
|
|
if score.save
|
|
render :text => 'scoring recorded'
|
|
else
|
|
render :text => "score invalid: #{score.errors.inspect}", status: 422
|
|
end
|
|
end
|
|
|
|
################# AVATAR #####################
|
|
|
|
def update_avatar
|
|
original_fpfile = params[:original_fpfile]
|
|
cropped_fpfile = params[:cropped_fpfile]
|
|
cropped_large_fpfile = params[:cropped_large_fpfile]
|
|
crop_selection = params[:crop_selection]
|
|
|
|
# public bucket to allow images to be available to public
|
|
@user.update_avatar(original_fpfile, cropped_fpfile, cropped_large_fpfile, crop_selection, Rails.application.config.aws_bucket_public)
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, status: :unprocessable_entity
|
|
else
|
|
respond_with @user, responder: ApiResponder, status: 200
|
|
end
|
|
end
|
|
|
|
def delete_avatar
|
|
@user.delete_avatar(Rails.application.config.aws_bucket_public)
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, status: :unprocessable_entity
|
|
else
|
|
respond_with @user, responder: ApiResponder, status: 204
|
|
end
|
|
end
|
|
|
|
def generate_filepicker_policy
|
|
# generates a soon-expiring filepicker policy so that a user can only upload to their own folder in their bucket
|
|
|
|
handle = params[:handle]
|
|
|
|
call = 'pick,convert,store'
|
|
|
|
policy = {:expiry => (DateTime.now + 5.minutes).to_i(),
|
|
:call => call,
|
|
#:path => 'avatars/' + @user.id + '/.*jpg'
|
|
}
|
|
|
|
# if the caller specifies a handle, add it to the hash
|
|
unless handle.nil?
|
|
start = handle.rindex('/') + 1
|
|
policy[:handle] = handle[start..-1]
|
|
end
|
|
|
|
policy = Base64.urlsafe_encode64(policy.to_json)
|
|
digest = OpenSSL::Digest.new('sha256')
|
|
signature = OpenSSL::HMAC.hexdigest(digest, Rails.application.config.fp_secret, policy)
|
|
|
|
render :json => {
|
|
:signature => signature,
|
|
:policy => policy
|
|
}, :status => :ok
|
|
end
|
|
|
|
|
|
###################### CRASH DUMPS #######################
|
|
|
|
# This is very similar to api_music_sessions#perf_upload
|
|
# This should largely be moved into a library somewhere in jam-ruby.
|
|
def crash_dump
|
|
# example of using curl to access this API:
|
|
# curl -L -T some_file -X PUT http://localhost:3000/api/dumps?client_type=[MacOSX/Win32/JamBox]&client_version=[VERSION]&client_id=[CLIENT_ID]&session_id=[SESSION_ID]×tamp=[TIMESTAMP]&fsize=10K&crash_context="Blahblahblab"
|
|
# user_id is deduced if possible from the user's cookie.
|
|
@dump = CrashDump.new
|
|
|
|
user = User.find_by_id(params[:user_id])
|
|
|
|
@dump.client_type = params[:client_type]
|
|
@dump.client_version = params[:client_version]
|
|
@dump.client_id = params[:client_id]
|
|
@dump.user_id = user.id if user
|
|
@dump.session_id = params[:session_id]
|
|
@dump.timestamp = params[:timestamp]
|
|
@dump.description = params[:description]
|
|
@dump.fsize = params[:fsize]
|
|
@dump.crash_context = params[:crash_context]
|
|
crash_date = params[:crash_date]
|
|
|
|
unless @dump.save
|
|
# There are at least some conditions on valid dumps (need client_type)
|
|
response.status = :unprocessable_entity
|
|
respond_with @dump
|
|
return
|
|
end
|
|
|
|
# This part is the piece that really needs to be decomposed into a library...
|
|
if Rails.application.config.storage_type == :fog
|
|
s3 = AWS::S3.new(:access_key_id => Rails.application.config.aws_access_key_id,
|
|
:secret_access_key => Rails.application.config.aws_secret_access_key)
|
|
bucket = s3.buckets[Rails.application.config.aws_bucket]
|
|
uri = @dump.uri
|
|
expire = Time.now + 20.years
|
|
read_url = bucket.objects[uri].url_for(:read,
|
|
:expires => expire,
|
|
:'response_content_type' => 'application/octet-stream').to_s
|
|
#@dump.update_attribute(:uri, read_url)
|
|
|
|
write_url = bucket.objects[uri].url_for(:write,
|
|
:expires => Rails.application.config.crash_dump_data_signed_url_timeout,
|
|
:'response_content_type' => 'application/octet-stream').to_s
|
|
|
|
logger.debug("crash_dump can read from url #{read_url}")
|
|
|
|
|
|
if user
|
|
body = "Client crash for user #{user.email} (#{user.name})\n"
|
|
body << "Client type: #{@dump.client_type}\n"
|
|
body << "Client version: #{@dump.client_version}\n"
|
|
body << "Download at: #{read_url}\n"
|
|
body << "User admin url: #{user.admin_url}\n"
|
|
body << "Actual Crash Date: #{crash_date}\n"
|
|
body << "File size: #{@dump.fsize}\n"
|
|
body << "Crash Context:\n\n#{@dump.crash_context}\n"
|
|
|
|
subject = "Crash for #{@dump.client_type} - #{user.email}, on #{crash_date}"
|
|
else
|
|
body = "Client crash for unknown user\n"
|
|
body << "Client type: #{@dump.client_type}\n"
|
|
body << "Client version: #{@dump.client_version}\n"
|
|
body << "Download at: #{read_url}\n"
|
|
body << "Actual Crash Date: #{crash_date}\n"
|
|
body << "File size: #{@dump.fsize}\n"
|
|
body << "Crash Context:\n\n#{@dump.crash_context}\n"
|
|
|
|
subject = "Crash for #{@dump.client_type} - unknown user), on #{crash_date}"
|
|
end
|
|
|
|
logger.debug("sending crash email with subject#{subject}")
|
|
AdminMailer.crash_alert(subject: subject, body: body).deliver_now
|
|
|
|
redirect_to write_url, status: 307
|
|
else
|
|
# we should store it here to aid in development, but we don't have to until someone wants the feature
|
|
# so... just return 200
|
|
render :json => {:id => @dump.id}, :status => 200
|
|
end
|
|
|
|
end
|
|
|
|
|
|
# user progression tracking
|
|
def downloaded_client
|
|
@user = current_user
|
|
@user.update_progression_field(:first_downloaded_client_at)
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, :status => :unprocessable_entity
|
|
return
|
|
end
|
|
render :json => {}, :status => 200
|
|
|
|
end
|
|
|
|
# user progression tracking
|
|
def qualified_gear
|
|
@user = current_user
|
|
if params[:success]
|
|
@user.update_progression_field(:first_certified_gear_at)
|
|
|
|
connection = Connection.find_by_client_id(params[:client_id])
|
|
# update last_jam location information
|
|
@user.update_addr_loc(connection, User::JAM_REASON_FTUE) if connection
|
|
|
|
if !@user.errors.any?
|
|
# update audio gear latency information
|
|
@user.update_audio_latency(connection, params[:audio_latency]) if params[:audio_latency]
|
|
end
|
|
else
|
|
@user.failed_qualification(params[:reason])
|
|
end
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, :status => :unprocessable_entity
|
|
return
|
|
end
|
|
|
|
render :json => {}, :status => 200
|
|
end
|
|
|
|
# user progression tracking
|
|
def social_promoted
|
|
@user = current_user
|
|
@user.update_progression_field(:first_social_promoted_at)
|
|
|
|
if @user.errors.any?
|
|
respond_with @user, :status => :unprocessable_entity
|
|
return
|
|
end
|
|
render :json => {}, :status => 200
|
|
end
|
|
|
|
def opened_jamtrack_web_player
|
|
User.where(id: current_user.id).update_all(first_opened_jamtrack_web_player: Time.now)
|
|
render :json => {}, :status => 200
|
|
end
|
|
|
|
def user_event
|
|
event = UserEvent.new
|
|
event.name = params[:name]
|
|
event.detail = params[:detail].to_json if params[:detail]
|
|
event.user_id = current_user.id if current_user
|
|
event.save
|
|
|
|
render :json => {}, :status => 200
|
|
end
|
|
|
|
# creates display-ready session data for sharing
|
|
def share_session
|
|
provider = params[:provider]
|
|
music_session_id = params[:music_session]
|
|
history = MusicSession.find(music_session_id)
|
|
|
|
if provider == 'facebook'
|
|
|
|
render json: {
|
|
description: view_context.description_for_music_session(history),
|
|
title: view_context.title_for_music_session(history, current_user),
|
|
photo_url: view_context.facebook_image_for_music_session(history),
|
|
url: share_token_url(history.share_token.token),
|
|
caption: 'www.jamkazam.com'
|
|
}, status: 200
|
|
|
|
elsif provider == 'twitter'
|
|
|
|
render json: {
|
|
message: view_context.title_for_music_session(history, current_user)
|
|
}, status: 200
|
|
|
|
else
|
|
render :json => {:errors => {:provider => ['not valid']}}, :status => 422
|
|
end
|
|
end
|
|
|
|
# creates display-ready recording data for sharing
|
|
def share_recording
|
|
provider = params[:provider]
|
|
claimed_recording_id = params[:claimed_recording]
|
|
claimed_recording = ClaimedRecording.find(claimed_recording_id)
|
|
|
|
if provider == 'facebook'
|
|
|
|
render json: {
|
|
description: view_context.description_for_claimed_recording(claimed_recording),
|
|
title: view_context.title_for_claimed_recording(claimed_recording, current_user),
|
|
photo_url: view_context.facebook_image_for_claimed_recording(claimed_recording),
|
|
url: share_token_url(claimed_recording.share_token.token),
|
|
caption: 'www.jamkazam.com'
|
|
}, status: 200
|
|
|
|
elsif provider == 'twitter'
|
|
|
|
render json: {
|
|
message: view_context.title_for_claimed_recording(history, current_user) + " at " + request.host_with_port
|
|
}, status: 200
|
|
|
|
|
|
else
|
|
render :json => {:errors => {:provider => ['not valid']}}, :status => 422
|
|
end
|
|
end
|
|
|
|
def affiliate_partner
|
|
if oo = current_user.affiliate_partner
|
|
if request.post?
|
|
oo.address = params[:address]
|
|
oo.tax_identifier = params[:tax_identifier]
|
|
oo.save!
|
|
render nothing: true
|
|
|
|
elsif request.get?
|
|
result = {}
|
|
result['account'] = {
|
|
'address' => oo.address.clone,
|
|
'tax_identifier' => oo.tax_identifier,
|
|
'entity_type' => oo.entity_type,
|
|
'partner_name' => oo.partner_name,
|
|
'partner_id' => oo.partner_user_id,
|
|
'id' => oo.id
|
|
}
|
|
if txt = oo.affiliate_legalese.try(:legalese)
|
|
txt = ControllerHelp.instance.simple_format(txt)
|
|
end
|
|
result['agreement'] = {
|
|
'legalese' => txt,
|
|
'signed_at' => oo.signed_at
|
|
}
|
|
#result['signups'] = oo.referrals_by_date
|
|
#result['earnings'] = [['April 2015', '1000 units', '$100']]
|
|
render json: result.to_json, status: 200
|
|
end
|
|
else
|
|
render :json => {:message => 'user not affiliate partner'}, :status => 400
|
|
end
|
|
end
|
|
|
|
def affiliate_report
|
|
begin
|
|
affiliate = User
|
|
.where(:id => params[:id])
|
|
.includes(:affiliate_partner)
|
|
.limit(1)
|
|
.first
|
|
.affiliate_partner
|
|
referrals_by_date = affiliate.referrals_by_date do |by_date|
|
|
by_date.inject([]) { |rr, key| rr << key }
|
|
end
|
|
result = {
|
|
:total_count => affiliate.referral_user_count,
|
|
:by_date => referrals_by_date
|
|
}
|
|
render json: result.to_json, status: 200
|
|
rescue
|
|
render :json => {:message => $!.to_s}, :status => 400
|
|
end
|
|
end
|
|
|
|
def add_play
|
|
if params[:id].blank?
|
|
render :json => {:message => "Playable ID is required"}, :status => 400
|
|
return
|
|
end
|
|
|
|
play = PlayablePlay.new
|
|
play.playable_id = params[:id]
|
|
play.playable_type = params[:playable_type]
|
|
play.player_id = params[:user_id]
|
|
play.claimed_recording_id = params[:claimed_recording_id]
|
|
play.ip_address = request.remote_ip
|
|
play.save
|
|
|
|
if play.errors.any?
|
|
render :json => {:errors => play.errors}, :status => 422
|
|
else
|
|
render :json => {}, :status => 201
|
|
end
|
|
end
|
|
|
|
# updates audio latency on the user, and associated connection
|
|
def audio_latency
|
|
Connection.transaction do
|
|
@user.update_audio_latency(Connection.find_by_client_id(params[:client_id]), params[:audio_latency])
|
|
respond_with_model(@user)
|
|
end
|
|
end
|
|
|
|
def udp_reachable
|
|
Connection.transaction do
|
|
@connection = Connection.find_by_client_id!(params[:client_id])
|
|
# deliberately don't updated_at on connection! only heartbeats do that
|
|
Connection.where(:id => @connection.id).update_all(:udp_reachable => params[:udp_reachable])
|
|
respond_with_model(@connection)
|
|
end
|
|
end
|
|
|
|
def is_network_testing
|
|
Connection.transaction do
|
|
@connection = Connection.find_by_client_id!(params[:client_id])
|
|
# deliberately don't updated_at on connection! only heartbeats do that
|
|
Connection.where(:id => @connection.id).update_all(:is_network_testing => params[:is_network_testing])
|
|
respond_with_model(@connection)
|
|
end
|
|
end
|
|
|
|
def validate_data
|
|
unless (data = params[:data]).present?
|
|
render(json: {message: "blank data #{data}"}, status: :unprocessable_entity) && return
|
|
end
|
|
url = nil
|
|
site = params[:sitetype]
|
|
if site.blank? || 'url'==site
|
|
url = data
|
|
elsif Utils.recording_source?(site)
|
|
rec_data = Utils.extract_recording_data(site, data)
|
|
if rec_data
|
|
render json: {message: 'Valid Site', recording_id: rec_data["id"], recording_title: rec_data["title"], data: data}, status: 200
|
|
return
|
|
else
|
|
render json: {message: 'Invalid Site', data: data, errors: {site: ["Could not detect recording identifier"]}}, status: 200
|
|
return
|
|
end
|
|
else
|
|
url = Utils.username_url(data, site)
|
|
end
|
|
unless url.blank?
|
|
if errmsg = Utils.site_validator(url, site)
|
|
render json: {message: 'Invalid Site', data: data, errors: {site: [errmsg]}}, status: 200
|
|
else
|
|
render json: {message: 'Valid Site', data: data}, status: 200
|
|
end
|
|
else
|
|
render json: {message: "unknown validation for data '#{params[:data]}', site '#{params[:site]}'"}, status: :unprocessable_entity
|
|
end
|
|
end
|
|
|
|
def broadcast_notification
|
|
@broadcast = BroadcastNotification.next_broadcast(current_user)
|
|
|
|
if @broadcast
|
|
# mark it as viewed
|
|
@broadcast.did_view(current_user)
|
|
respond_with_model(@broadcast)
|
|
else
|
|
render json: {}, status: 200
|
|
end
|
|
end
|
|
|
|
# used to hide a broadcast notification from rotation temporarily
|
|
def quiet_broadcast_notification
|
|
@broadcast = BroadcastNotificationView.find_by_broadcast_notification_id_and_user_id(params[:broadcast_id], current_user.id)
|
|
|
|
if @broadcast
|
|
@broadcast.active_at = Date.today + 14 # 14 days in the future we'll re-instas
|
|
@broadcast.save
|
|
end
|
|
|
|
render json: {}, status: 200
|
|
end
|
|
|
|
def lookup_user
|
|
|
|
User.includes([{musician_instruments: :instrument},
|
|
{band_musicians: :user},
|
|
{genre_players: :genre},
|
|
:bands, :instruments, :genres, :jam_track_rights,
|
|
:affiliate_partner, :reviews, :review_summary, :recordings,
|
|
:teacher => [:subjects, :instruments, :languages, :genres, :teachers_languages, :experiences_teaching, :experiences_award, :experiences_education, :reviews, :review_summary]])
|
|
.find(params[:id])
|
|
end
|
|
|
|
def try_posa_card
|
|
@posa_card = PosaCard.find_by_code(params[:gift_card])
|
|
|
|
if @posa_card.nil?
|
|
return false
|
|
end
|
|
|
|
@posa_card.claim(current_user)
|
|
|
|
if @posa_card.errors.any?
|
|
respond_with_model(@posa_card)
|
|
else
|
|
if @posa_card.is_lesson_posa_card?
|
|
render json: {gifted_jamclass: @posa_card.credits}, status: 200
|
|
elsif @posa_card.card_type == PosaCard::JAM_TRACKS_10
|
|
render json: {gifted_jamtracks: @posa_card.credits}, status: 200
|
|
elsif @posa_card.card_type == PosaCard::JAM_TRACKS_5
|
|
render json: {gifted_jamtracks: @posa_card.credits}, status: 200
|
|
else
|
|
raise 'unknown card_type ' + @posa_card.card_type
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def try_gift_card
|
|
|
|
@gift_card = GiftCard.find_by_code(params[:gift_card])
|
|
|
|
if @gift_card.nil?
|
|
render json: {errors: {gift_card: ['does not exist']}}, status: 422
|
|
return
|
|
end
|
|
|
|
if current_user.gift_cards.count >= 5
|
|
render json: {errors: {gift_card: ['has too many on account']}}, status: 422
|
|
return
|
|
end
|
|
|
|
if @gift_card.user
|
|
if @gift_card.user == current_user
|
|
render json: {errors: {gift_card: ['already redeemed by you']}}, status: 422
|
|
return
|
|
else
|
|
render json: {errors: {gift_card: ['already redeemed by another']}}, status: 422
|
|
return
|
|
end
|
|
end
|
|
|
|
@gift_card.user = current_user
|
|
@gift_card.save
|
|
|
|
if @gift_card.errors.any?
|
|
respond_with_model(@gift_card)
|
|
return
|
|
else
|
|
|
|
UserWhitelist.card_create(current_user, 'giftcard')
|
|
# apply gift card items to everything in shopping cart
|
|
current_user.reload
|
|
ShoppingCart.apply_gifted_jamtracks(current_user)
|
|
render json: {gifted_jamtracks: current_user.gifted_jamtracks}, status: 200
|
|
end
|
|
end
|
|
|
|
def redeem_giftcard
|
|
|
|
# first, try to find posa_card
|
|
rendered = try_posa_card
|
|
|
|
try_gift_card if !rendered
|
|
|
|
end
|
|
|
|
def test_drive_status
|
|
@user = current_user
|
|
@teacher = User.find(params[:teacher_id])
|
|
end
|
|
|
|
###################### RECORDINGS #######################
|
|
# def recording_index
|
|
# @recordings = User.recording_index(current_user, params[:id])
|
|
# respond_with @recordings, responder: ApiResponder, :status => 200
|
|
# end
|
|
|
|
# def recording_show
|
|
# hide_private = false
|
|
|
|
# # hide private recordings from anyone but the current user
|
|
# if current_user.id != params[:id]
|
|
# hide_private = true
|
|
# end
|
|
|
|
# @recording = Recording.find(params[:recording_id])
|
|
# if !@recording.public && hide_private
|
|
# render :json => { :message => "You are not allowed to access this recording." }, :status => 403
|
|
# #respond_with "You are not allowed to access this recording.", responder: ApiResponder, :status => 403
|
|
# else
|
|
# respond_with @recording, responder: ApiResponder, :status => 200
|
|
# end
|
|
# end
|
|
|
|
# def recording_create
|
|
# @recording = Recording.save(params[:recording_id],
|
|
# params[:public],
|
|
# params[:description],
|
|
# params[:genres],
|
|
# current_user.id,
|
|
# params[:id],
|
|
# false)
|
|
|
|
# @user = current_user
|
|
# respond_with @recording, responder: ApiResponder, :status => 201, :location => api_recording_detail_url(@user, @recording)
|
|
# end
|
|
|
|
# def recording_update
|
|
# @recording = Recording.save(params[:recording_id],
|
|
# params[:public],
|
|
# params[:description],
|
|
# params[:genres],
|
|
# current_user.id,
|
|
# params[:id],
|
|
# false)
|
|
|
|
# respond_with @recording, responder: ApiResponder, :status => 200
|
|
# end
|
|
|
|
# def recording_destroy
|
|
# @recording = Recording.find(params[:recording_id])
|
|
# @recording.delete
|
|
# respond_with responder: ApiResponder, :status => 204
|
|
# end
|
|
end
|