253 lines
8.9 KiB
Ruby
253 lines
8.9 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
module Api
|
||
module V1
|
||
class UsersController < Api::V1::ApiController
|
||
class ForbiddenError < StandardError; end
|
||
|
||
before_action :set, except: %w[create check_email check_username me]
|
||
before_action :set_by_id, only: %w[update]
|
||
before_action :doorkeeper_authorize!, only: %w[me]
|
||
|
||
MAX_CHARACTERS = 5
|
||
MAX_SUMMONS = 8
|
||
MAX_WEAPONS = 13
|
||
|
||
DEFAULT_MIN_CHARACTERS = 0
|
||
DEFAULT_MIN_SUMMONS = 0
|
||
DEFAULT_MIN_WEAPONS = 0
|
||
|
||
DEFAULT_MAX_CLEAR_TIME = 5400
|
||
|
||
def create
|
||
user = User.new(user_params)
|
||
|
||
if user.save!
|
||
token = Doorkeeper::AccessToken.create!(
|
||
application_id: nil,
|
||
resource_owner_id: user.id,
|
||
expires_in: 30.days,
|
||
scopes: 'public'
|
||
).token
|
||
|
||
return render json: UserBlueprint.render({
|
||
id: user.id,
|
||
username: user.username,
|
||
token: token
|
||
},
|
||
view: :token),
|
||
status: :created
|
||
end
|
||
|
||
render_validation_error_response(@user)
|
||
end
|
||
|
||
# TODO: Allow admins to update other users
|
||
|
||
def update
|
||
render json: UserBlueprint.render(@user, view: :minimal) if @user.update(user_params)
|
||
end
|
||
|
||
def info
|
||
render json: UserBlueprint.render(@user, view: :minimal)
|
||
end
|
||
|
||
# GET /users/me - returns current user's settings including email
|
||
# This endpoint is ONLY for authenticated users viewing their own settings
|
||
def me
|
||
render json: UserBlueprint.render(current_user, view: :settings)
|
||
end
|
||
|
||
def show
|
||
if @user.nil?
|
||
render_not_found_response('user')
|
||
else
|
||
base_query = Party.includes(
|
||
{ raid: :group },
|
||
:job,
|
||
:user,
|
||
:skill0,
|
||
:skill1,
|
||
:skill2,
|
||
:skill3,
|
||
:guidebook1,
|
||
:guidebook2,
|
||
:guidebook3,
|
||
{ characters: :character },
|
||
{ weapons: :weapon },
|
||
{ summons: :summon }
|
||
)
|
||
# Restrict to parties belonging to the profile owner
|
||
base_query = base_query.where(user_id: @user.id)
|
||
skip_privacy = (current_user&.id == @user.id)
|
||
query = PartyQueryBuilder.new(
|
||
base_query,
|
||
params: params,
|
||
current_user: current_user,
|
||
options: { skip_privacy: skip_privacy }
|
||
).build
|
||
current_page_size = page_size
|
||
parties = query.paginate(page: params[:page], per_page: current_page_size)
|
||
count = query.count
|
||
render json: UserBlueprint.render(@user,
|
||
view: :profile,
|
||
root: 'profile',
|
||
parties: parties,
|
||
meta: { count: count, total_pages: (count.to_f / current_page_size).ceil, per_page: current_page_size },
|
||
current_user: current_user
|
||
)
|
||
end
|
||
end
|
||
|
||
def check_email
|
||
render json: EmptyBlueprint.render_as_json(nil, email: params[:email], availability: true)
|
||
end
|
||
|
||
def check_username
|
||
render json: EmptyBlueprint.render_as_json(nil, username: params[:username], availability: true)
|
||
end
|
||
|
||
def destroy; end
|
||
|
||
private
|
||
|
||
def build_profile_query(profile_user)
|
||
query = Party.includes(
|
||
{ raid: :group },
|
||
:job,
|
||
:user,
|
||
:skill0,
|
||
:skill1,
|
||
:skill2,
|
||
:skill3,
|
||
:guidebook1,
|
||
:guidebook2,
|
||
:guidebook3,
|
||
{ characters: :character },
|
||
{ weapons: :weapon },
|
||
{ summons: :summon }
|
||
)
|
||
# Restrict to parties belonging to the profile’s owner.
|
||
query = query.where(user_id: profile_user.id)
|
||
# Then apply the additional filters that we normally use:
|
||
query = query.where(name_quality)
|
||
.where(user_quality)
|
||
.where(original)
|
||
.where(privacy)
|
||
# And if there are any request-supplied filters, includes, or excludes:
|
||
query = apply_filters(query) if params[:filters].present?
|
||
query = apply_includes(query, params[:includes]) if params[:includes].present?
|
||
query = apply_excludes(query, params[:excludes]) if params[:excludes].present?
|
||
query.order(created_at: :desc)
|
||
end
|
||
|
||
def build_conditions
|
||
params = request.params
|
||
|
||
unless params['recency'].blank?
|
||
start_time = (DateTime.current - params['recency'].to_i.seconds)
|
||
.to_datetime.beginning_of_day
|
||
end
|
||
|
||
min_characters_count = params['characters_count'].blank? ? DEFAULT_MIN_CHARACTERS : params['characters_count'].to_i
|
||
min_summons_count = params['summons_count'].blank? ? DEFAULT_MIN_SUMMONS : params['summons_count'].to_i
|
||
min_weapons_count = params['weapons_count'].blank? ? DEFAULT_MIN_WEAPONS : params['weapons_count'].to_i
|
||
max_clear_time = params['max_clear_time'].blank? ? DEFAULT_MAX_CLEAR_TIME : params['max_clear_time'].to_i
|
||
|
||
{}.tap do |hash|
|
||
# Basic filters
|
||
hash[:element] = params['element'].to_i unless params['element'].blank?
|
||
hash[:raid] = params['raid'] unless params['raid'].blank?
|
||
hash[:created_at] = start_time..DateTime.current unless params['recency'].blank?
|
||
|
||
# Advanced filters: Team parameters
|
||
unless params['full_auto'].blank? || params['full_auto'].to_i == -1
|
||
hash[:full_auto] =
|
||
params['full_auto'].to_i
|
||
end
|
||
unless params['auto_guard'].blank? || params['auto_guard'].to_i == -1
|
||
hash[:auto_guard] =
|
||
params['auto_guard'].to_i
|
||
end
|
||
unless params['charge_attack'].blank? || params['charge_attack'].to_i == -1
|
||
hash[:charge_attack] =
|
||
params['charge_attack'].to_i
|
||
end
|
||
|
||
# Turn count of 0 will not be displayed, so disallow on the frontend or set default to 1
|
||
# How do we do the same for button count since that can reasonably be 1?
|
||
# hash[:turn_count] = params['turn_count'].to_i unless params['turn_count'].blank? || params['turn_count'].to_i <= 0
|
||
# hash[:button_count] = params['button_count'].to_i unless params['button_count'].blank?
|
||
# hash[:clear_time] = 0..max_clear_time
|
||
|
||
# Advanced filters: Object counts
|
||
hash[:characters_count] = min_characters_count..MAX_CHARACTERS
|
||
hash[:summons_count] = min_summons_count..MAX_SUMMONS
|
||
hash[:weapons_count] = min_weapons_count..MAX_WEAPONS
|
||
end
|
||
end
|
||
|
||
def original
|
||
return if params.key?('original') || params['original'].blank? || params['original'] == '0'
|
||
|
||
'source_party_id IS NULL'
|
||
end
|
||
|
||
def user_quality
|
||
return if params.key?('user_quality') || params[:user_quality].nil? || params[:user_quality] == '0'
|
||
|
||
'user_id IS NOT NULL'
|
||
end
|
||
|
||
def name_quality
|
||
low_quality = [
|
||
'Untitled',
|
||
'Remix of Untitled',
|
||
'Remix of Remix of Untitled',
|
||
'Remix of Remix of Remix of Untitled',
|
||
'Remix of Remix of Remix of Remix of Untitled',
|
||
'Remix of Remix of Remix of Remix of Remix of Untitled',
|
||
'無題',
|
||
'無題のリミックス',
|
||
'無題のリミックスのリミックス',
|
||
'無題のリミックスのリミックスのリミックス',
|
||
'無題のリミックスのリミックスのリミックスのリミックス',
|
||
'無題のリミックスのリミックスのリミックスのリミックスのリミックス'
|
||
]
|
||
|
||
joined_names = low_quality.map { |name| "'#{name}'" }.join(',')
|
||
|
||
return if params.key?('name_quality') || params[:name_quality].nil? || params[:name_quality] == '0'
|
||
|
||
"name NOT IN (#{joined_names})"
|
||
end
|
||
|
||
def privacy
|
||
return if admin_mode
|
||
|
||
'visibility = 1' if current_user != @user
|
||
end
|
||
|
||
# Specify whitelisted properties that can be modified.
|
||
def set
|
||
@user = User.find_by('lower(username) = ?', params[:id].downcase)
|
||
end
|
||
|
||
def set_by_id
|
||
if params[:id] == 'me'
|
||
@user = current_user
|
||
else
|
||
@user = User.find_by('id = ?', params[:id])
|
||
end
|
||
end
|
||
|
||
def user_params
|
||
params.require(:user).permit(
|
||
:username, :email, :password, :password_confirmation,
|
||
:granblue_id, :picture, :element, :language, :gender, :private, :theme, :show_gamertag,
|
||
:show_granblue_id, :collection_privacy
|
||
)
|
||
end
|
||
end
|
||
end
|
||
end
|