- Split PartiesController into three concerns - Implemented testing for PartiesController and two concerns - Implemented fixes across other files to ensure PartiesController tests pass - Added Favorites factory
164 lines
5.5 KiB
Ruby
164 lines
5.5 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
module PartyQueryingConcern
|
||
extend ActiveSupport::Concern
|
||
include PartyConstants
|
||
|
||
# Builds the base query for parties with all required associations.
|
||
def build_parties_query(favorites: false)
|
||
query = Party.includes(
|
||
{ raid: :group },
|
||
:job,
|
||
:user,
|
||
:skill0, :skill1, :skill2, :skill3,
|
||
:guidebook1, :guidebook2, :guidebook3,
|
||
{ characters: :character },
|
||
{ weapons: :weapon },
|
||
{ summons: :summon }
|
||
)
|
||
query = if favorites
|
||
query.joins(:favorites)
|
||
.where(favorites: { user_id: current_user.id })
|
||
.distinct.order(created_at: :desc)
|
||
else
|
||
query.order(visibility: :asc, created_at: :desc)
|
||
end
|
||
query = apply_filters(query)
|
||
query = apply_privacy_settings(query, favorites: false)
|
||
query = apply_includes(query, params[:includes]) if params[:includes].present?
|
||
query = apply_excludes(query, params[:excludes]) if params[:excludes].present?
|
||
query
|
||
end
|
||
|
||
# Renders paginated parties using PartyBlueprint.
|
||
def render_paginated_parties(parties)
|
||
render json: Api::V1::PartyBlueprint.render(
|
||
parties,
|
||
view: :preview,
|
||
root: :results,
|
||
meta: {
|
||
count: parties.total_entries,
|
||
total_pages: parties.total_pages,
|
||
per_page: PartyConstants::COLLECTION_PER_PAGE
|
||
},
|
||
current_user: current_user
|
||
)
|
||
end
|
||
|
||
# Applies filters to the query.
|
||
def apply_filters(query)
|
||
conditions = build_filters
|
||
|
||
query = query.where(conditions)
|
||
query = query.where(name_quality) if params[:name_quality].present?
|
||
query.where(
|
||
weapons_count: build_count(params[:weapons_count], PartyConstants::DEFAULT_MIN_WEAPONS)..PartyConstants::MAX_WEAPONS,
|
||
characters_count: build_count(params[:characters_count], PartyConstants::DEFAULT_MIN_CHARACTERS)..PartyConstants::MAX_CHARACTERS,
|
||
summons_count: build_count(params[:summons_count], PartyConstants::DEFAULT_MIN_SUMMONS)..PartyConstants::MAX_SUMMONS
|
||
)
|
||
end
|
||
|
||
# Applies privacy settings based on whether the current user is an admin.
|
||
def apply_privacy_settings(query, favorites: false)
|
||
return query if admin_mode
|
||
|
||
if favorites.present?
|
||
query.where('visibility < 3')
|
||
else
|
||
query.where(visibility: 1)
|
||
end
|
||
end
|
||
|
||
# Builds filtering conditions from request parameters.
|
||
def build_filters
|
||
{
|
||
element: params[:element].present? ? params[:element].to_i : nil,
|
||
raid_id: params[:raid],
|
||
created_at: build_date_range,
|
||
full_auto: build_option(params[:full_auto]),
|
||
auto_guard: build_option(params[:auto_guard]),
|
||
charge_attack: build_option(params[:charge_attack]),
|
||
characters_count: build_count(params[:characters_count], PartyConstants::DEFAULT_MIN_CHARACTERS)..PartyConstants::MAX_CHARACTERS,
|
||
summons_count: build_count(params[:summons_count], PartyConstants::DEFAULT_MIN_SUMMONS)..PartyConstants::MAX_SUMMONS,
|
||
weapons_count: build_count(params[:weapons_count], PartyConstants::DEFAULT_MIN_WEAPONS)..PartyConstants::MAX_WEAPONS
|
||
}.compact
|
||
end
|
||
|
||
# Returns a date range based on the recency parameter.
|
||
def build_date_range
|
||
return nil unless params[:recency].present?
|
||
|
||
start_time = DateTime.current - params[:recency].to_i.seconds
|
||
start_time.beginning_of_day..DateTime.current
|
||
end
|
||
|
||
# Returns the count value or a default if blank.
|
||
def build_count(value, default)
|
||
value.blank? ? default : value.to_i
|
||
end
|
||
|
||
# Processes an option parameter.
|
||
def build_option(value)
|
||
value.to_i unless value.blank? || value.to_i == -1
|
||
end
|
||
|
||
# Applies “includes” filtering for objects in the party.
|
||
def apply_includes(query, includes)
|
||
includes.split(',').each do |id|
|
||
grid_table, object_table = grid_table_and_object_table(id)
|
||
next unless grid_table && object_table
|
||
|
||
condition = <<-SQL.squish
|
||
EXISTS (
|
||
SELECT 1 FROM #{grid_table}
|
||
JOIN #{object_table} ON #{grid_table}.#{object_table.singularize}_id = #{object_table}.id
|
||
WHERE #{object_table}.granblue_id = ? AND #{grid_table}.party_id = parties.id
|
||
)
|
||
SQL
|
||
query = query.where(condition, id)
|
||
end
|
||
query
|
||
end
|
||
|
||
# Applies “excludes” filtering for objects in the party.
|
||
def apply_excludes(query, excludes)
|
||
excludes.split(',').each do |id|
|
||
grid_table, object_table = grid_table_and_object_table(id)
|
||
next unless grid_table && object_table
|
||
|
||
condition = <<-SQL.squish
|
||
NOT EXISTS (
|
||
SELECT 1 FROM #{grid_table}
|
||
JOIN #{object_table} ON #{grid_table}.#{object_table.singularize}_id = #{object_table}.id
|
||
WHERE #{object_table}.granblue_id = ? AND #{grid_table}.party_id = parties.id
|
||
)
|
||
SQL
|
||
query = query.where(condition, id)
|
||
end
|
||
query
|
||
end
|
||
|
||
# Maps an id’s prefix to the corresponding grid and object table names.
|
||
def grid_table_and_object_table(id)
|
||
case id[0]
|
||
when '3' then %w[grid_characters characters]
|
||
when '2' then %w[grid_summons summons]
|
||
when '1' then %w[grid_weapons weapons]
|
||
else [nil, nil]
|
||
end
|
||
end
|
||
|
||
# Returns a remixed party name based on the current party name and current_user language.
|
||
def remixed_name(name)
|
||
blanked_name = { en: name.blank? ? 'Untitled team' : name, ja: name.blank? ? '無名の編成' : name }
|
||
if current_user
|
||
case current_user.language
|
||
when 'en' then "Remix of #{blanked_name[:en]}"
|
||
when 'ja' then "#{blanked_name[:ja]}のリミックス"
|
||
else "Remix of #{blanked_name[:en]}"
|
||
end
|
||
else
|
||
"Remix of #{blanked_name[:en]}"
|
||
end
|
||
end
|
||
end
|