584 lines
20 KiB
Ruby
584 lines
20 KiB
Ruby
class ApiUsersController < ApiController
|
|
|
|
before_filter :api_signed_in_user, :except => [:create, :signup_confirm, :auth_session_create, :complete, :finalize_update_email, :isp_scoring]
|
|
before_filter :auth_user, :only => [:session_settings_show, :session_history_index, :session_user_history_index, :update, :delete,
|
|
:like_create, :like_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]
|
|
|
|
respond_to :json
|
|
|
|
def index
|
|
# don't return users that aren't yet confirmed
|
|
@users = User.where('email_confirmed=TRUE').paginate(page: params[:page])
|
|
respond_with @users, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def show
|
|
# don't return users that aren't yet confirmed
|
|
@user = User.where('email_confirmed=TRUE').find(params[:id])
|
|
respond_with @user, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
# this API call is disabled by virtue of it being commented out in routes.rb
|
|
# the reason is that it has no captcha, and is therefore a bit abuseable
|
|
# if someone wants to use it, please add in captcha or some other bot-protector
|
|
def create
|
|
# sends email to email account for confirmation
|
|
@user = UserManager.new.signup(params[:first_name],
|
|
params[:last_name],
|
|
params[:email],
|
|
params[:password],
|
|
params[:password_confirmation],
|
|
params[:city],
|
|
params[:state],
|
|
params[:country],
|
|
params[:instruments],
|
|
params[:photo_url],
|
|
ApplicationHelper.base_uri(request) + "/confirm")
|
|
|
|
# check for errors
|
|
unless @user.errors.any?
|
|
render :json => {}, :status => :ok # an empty response, but 200 OK
|
|
else
|
|
response.status = :unprocessable_entity
|
|
respond_with @user, responder: ApiResponder
|
|
end
|
|
end
|
|
|
|
def update
|
|
@user = User.save(params[:id],
|
|
current_user.id,
|
|
params[:first_name],
|
|
params[:last_name],
|
|
nil, # Don't allow changing email here, since updating email is something that must be done through it's own API
|
|
nil, # Don't allow changing password here, since we want to prompt again for the old password
|
|
nil,
|
|
params[:musician],
|
|
params[:gender],
|
|
params[:birth_date],
|
|
params[:internet_service_provider],
|
|
params[:city],
|
|
params[:state],
|
|
params[:country],
|
|
params[:instruments].nil? ? [] : params[:instruments], # we have to convert nil to empty []. background: http://stackoverflow.com/questions/14647731/rails-converts-empty-arrays-into-nils-in-params-of-the-request
|
|
params[:photo_url])
|
|
|
|
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 @user.my_session_settings, 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 like_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def band_like_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def like_create
|
|
id = params[:id]
|
|
|
|
if !params[:user_id].nil?
|
|
User.create_user_like(params[:user_id], id)
|
|
respond_with @user, responder: ApiResponder, :location => api_user_like_index_url(@user)
|
|
|
|
elsif !params[:band_id].nil?
|
|
User.create_band_like(params[:band_id], id)
|
|
respond_with @user, responder: ApiResponder, :location => api_band_like_index_url(@user)
|
|
end
|
|
end
|
|
|
|
def like_destroy
|
|
if !params[:user_id].nil?
|
|
User.delete_like(params[:user_id], nil, params[:id])
|
|
|
|
elsif !params[:band_id].nil?
|
|
User.delete_like(nil, params[:band_id], params[:id])
|
|
end
|
|
|
|
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_show
|
|
@following = UserFollowing.find_by_user_id_and_follower_id(params[:user_id], params[:id])
|
|
end
|
|
|
|
def band_following_index
|
|
@user = User.find(params[:id])
|
|
end
|
|
|
|
def band_following_show
|
|
@following = BandFollowing.find_by_band_id_and_follower_id(params[:band_id], params[:id])
|
|
end
|
|
|
|
def following_create
|
|
id = params[:id]
|
|
|
|
if !params[:user_id].nil?
|
|
User.create_user_following(params[:user_id], id)
|
|
respond_with @user, responder: ApiResponder, :location => api_user_following_index_url(@user)
|
|
|
|
elsif !params[:band_id].nil?
|
|
User.create_band_following(params[:band_id], id)
|
|
respond_with @user, responder: ApiResponder, :location => api_band_following_index_url(@user)
|
|
end
|
|
end
|
|
|
|
def following_destroy
|
|
if !params[:user_id].nil?
|
|
User.delete_following(params[:user_id], nil, params[:id])
|
|
|
|
elsif !params[:band_id].nil?
|
|
User.delete_following(nil, params[:band_id], params[:id])
|
|
end
|
|
|
|
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])
|
|
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
|
|
@notifications = @user.notifications
|
|
respond_with @notifications, responder: ApiResponder, :status => 200
|
|
end
|
|
|
|
def notification_destroy
|
|
Notification.delete(params[:notification_id])
|
|
respond_with responder: ApiResponder, :status => 204
|
|
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
|
|
if request.post?
|
|
data = request.body.read
|
|
User.connection.execute("INSERT INTO isp_score_batch(json_scoring_data) VALUES ('#{data}')")
|
|
render :text => 'scoring recorded'
|
|
return
|
|
end
|
|
render :nothing => true
|
|
end
|
|
|
|
################# AVATAR #####################
|
|
|
|
def update_avatar
|
|
original_fpfile = params[:original_fpfile]
|
|
cropped_fpfile = params[:cropped_fpfile]
|
|
crop_selection = params[:crop_selection]
|
|
|
|
# public bucket to allow images to be available to public
|
|
@user.update_avatar(original_fpfile, cropped_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::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/users/dump.json?client_type=[MACOSX/Win32/JamBox]&client_id=[CLIENT_ID]&session_id=[SESSION_ID]
|
|
# user_id is deduced if possible from the cookie.
|
|
|
|
@dump.client_type = params[:client_type]
|
|
@dump.client_id = params[:client_id]
|
|
@dump.user_id = current_user
|
|
@dump.session_id = params[:session_id]
|
|
|
|
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 SampleApp::Application.config.storage_type == :fog
|
|
s3 = AWS::S3.new(:access_key_id => SampleApp::Application.config.aws_access_key_id,
|
|
:secret_access_key => SampleApp::Application.config.aws_secret_access_key)
|
|
# Fixme: Should we use the same bucket for everything?
|
|
bucket = s3.buckets[SampleApp::Application.config.aws_bucket]
|
|
url = bucket.objects[@dump.uri].url_for(:write, :expires => SampleApp::Application.config.crash_dump_data_signed_url_timeout, :'response_content_type' => 'application/octet-stream').to_s
|
|
|
|
logger.debug("crash_dump can upload to url #{url}")
|
|
|
|
redirect_to url
|
|
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
|
|
|
|
###################### 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
|