Merge main into gbf-wiki

This commit is contained in:
Justin Edmund 2023-07-16 02:07:33 -07:00
commit 32f4c27637
183 changed files with 5188 additions and 2756 deletions

2
.gitignore vendored
View file

@ -44,3 +44,5 @@ config/application.yml
.idea/*
.vscode/*
/config/credentials/production.key

View file

@ -71,12 +71,16 @@ end
group :development do
gem 'listen'
gem 'rubocop'
gem 'solargraph'
gem 'spring'
gem 'spring-commands-rspec'
end
group :tools do
gem 'squasher', '>= 0.6.0'
gem 'rubocop'
end
group :test do
gem 'api_matchers'
gem 'byebug'

View file

@ -304,6 +304,7 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
squasher (0.7.2)
stringio (3.0.4)
thor (1.2.1)
tilt (2.0.11)
@ -362,6 +363,7 @@ DEPENDENCIES
spring
spring-commands-rspec
sprockets-rails
squasher (>= 0.6.0)
will_paginate (~> 3.3)
RUBY VERSION

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
module Api
module V1
class AwakeningBlueprint < ApiBlueprint
field :name do |w|
{
en: w.name_en,
ja: w.name_jp
}
end
fields :slug, :object_type, :order
end
end
end

View file

@ -63,6 +63,12 @@ module Api
ougi_ratio_flb: w.ougi_ratio_flb
}
end
field :awakenings do
Awakening.where(object_type: 'Character').map do |a|
AwakeningBlueprint.render_as_hash(a)
end
end
end
end
end

View file

@ -18,6 +18,7 @@ module Api
end
field :awakening do |c|
<<<<<<< HEAD
c.awakening
end
@ -34,6 +35,31 @@ module Api
rings
end
field :aetherial_mastery, if: lambda { |_fn, obj, _opt|
!obj.earring['modifier'].nil?
} do |c|
c.earring
=======
{
type: AwakeningBlueprint.render_as_hash(c.awakening),
level: c.awakening_level
}
>>>>>>> main
end
field :over_mastery, if: lambda { |_fn, obj, _opt|
!obj.ring1['modifier'].nil? && !obj.ring2['modifier'].nil?
} do |c|
rings = []
rings.push(c.ring1) unless c.ring1['modifier'].nil?
rings.push(c.ring2) unless c.ring2['modifier'].nil?
rings.push(c.ring3) unless c.ring3['modifier'].nil?
rings.push(c.ring4) unless c.ring4['modifier'].nil?
rings
end
field :aetherial_mastery, if: lambda { |_fn, obj, _opt|
!obj.earring['modifier'].nil?
} do |c|

View file

@ -9,7 +9,11 @@ module Api
end
view :nested do
<<<<<<< HEAD
fields :main, :friend, :position, :uncap_level, :transcendence_step
=======
fields :main, :friend, :position, :quick_summon, :uncap_level, :transcendence_step
>>>>>>> main
association :summon, name: :object, blueprint: SummonBlueprint
end

View file

@ -32,9 +32,9 @@ module Api
end
end
field :awakening, if: ->(_field_name, w, _options) { w.weapon.awakening } do |w|
field :awakening, if: ->(_field_name, w, _options) { w.awakening_id } do |w|
{
type: w.awakening_type,
type: AwakeningBlueprint.render_as_hash(w.awakening),
level: w.awakening_level
}
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Api
module V1
class GuidebookBlueprint < ApiBlueprint
field :name do |book|
{
en: book.name_en,
ja: book.name_jp
}
end
field :description do |book|
{
en: book.description_en,
ja: book.description_jp
}
end
fields :granblue_id
end
end
end

View file

@ -17,7 +17,13 @@ module Api
]
end
<<<<<<< HEAD
fields :granblue_id, :row, :ml, :order
=======
fields :granblue_id, :row, :order,
:master_level, :ultimate_mastery,
:accessory, :accessory_type
>>>>>>> main
end
end
end

View file

@ -33,15 +33,25 @@ module Api
end
view :minimal do
fields :name, :element, :shortcode, :favorited, :extra,
:full_auto, :clear_time, :auto_guard, :created_at, :updated_at
fields :name, :element, :shortcode, :favorited, :remix,
:extra, :full_auto, :clear_time, :auto_guard, :auto_summon,
:created_at, :updated_at
field :guidebooks do |p|
{
'1' => !p.guidebook1.nil? ? GuidebookBlueprint.render_as_hash(p.guidebook1) : nil,
'2' => !p.guidebook2.nil? ? GuidebookBlueprint.render_as_hash(p.guidebook2) : nil,
'3' => !p.guidebook3.nil? ? GuidebookBlueprint.render_as_hash(p.guidebook3) : nil
}
end
field :remix do |p|
p.is_remix
end
association :raid,
blueprint: RaidBlueprint
blueprint: RaidBlueprint,
view: :full
association :job,
blueprint: JobBlueprint
@ -68,9 +78,18 @@ module Api
include_view :characters
include_view :job_skills
<<<<<<< HEAD
association :accessory,
blueprint: JobAccessoryBlueprint
fields :description, :charge_attack, :button_count, :turn_count, :chain_count
=======
fields :local_id, :description, :charge_attack,
:button_count, :turn_count, :chain_count,
:master_level, :ultimate_mastery
association :accessory,
blueprint: JobAccessoryBlueprint
>>>>>>> main
association :source_party,
blueprint: PartyBlueprint,
@ -86,6 +105,11 @@ module Api
include_view :preview
end
view :created do
include_view :full
fields :edit_key
end
view :destroyed do
fields :name, :description, :created_at, :updated_at
end

View file

@ -3,14 +3,21 @@
module Api
module V1
class RaidBlueprint < ApiBlueprint
field :name do |raid|
{
en: raid.name_en,
ja: raid.name_jp
}
view :nested do
field :name do |raid|
{
en: raid.name_en,
ja: raid.name_jp
}
end
fields :slug, :level, :element
end
fields :slug, :level, :group, :element
view :full do
include_view :nested
association :group, blueprint: RaidGroupBlueprint, view: :flat
end
end
end
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Api
module V1
class RaidGroupBlueprint < ApiBlueprint
view :flat do
field :name do |group|
{
en: group.name_en,
ja: group.name_jp
}
end
fields :difficulty, :order, :section, :extra, :guidebooks, :hl
end
view :full do
include_view :flat
association :raids, blueprint: RaidBlueprint, view: :full
end
end
end
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
module Api
module V1
class SearchBlueprint < Blueprinter::Base
identifier :searchable_id
fields :searchable_type, :granblue_id, :name_en, :name_jp, :element
end
end
end

View file

@ -11,8 +11,8 @@ module Api
end
fields :granblue_id, :element, :proficiency,
:max_level, :max_skill_level, :limit, :rarity,
:series, :ax, :ax_type, :awakening
:max_level, :max_skill_level, :max_awakening_level, :limit, :rarity,
:series, :ax, :ax_type
field :uncap do |w|
{
@ -38,6 +38,12 @@ module Api
max_atk_ulb: w.max_atk_ulb
}
end
field :awakenings, if: lambda { |_fn, obj, _opt| obj.awakenings.length.positive? } do |w|
w.awakenings.map do |a|
AwakeningBlueprint.render_as_hash(a)
end
end
end
end
end

View file

@ -10,7 +10,7 @@ module Api
}
end
fields :slug, :series, :slot, :group, :order
fields :granblue_id, :slug, :series, :slot, :group, :order
end
end
end

View file

@ -50,6 +50,12 @@ module Api
@current_user
end
def edit_key
@edit_key ||= request.headers['X-Edit-Key'] if request.headers['X-Edit-Key']
@edit_key
end
# Set the response content-type
def content_type(content_type)
response.headers['Content-Type'] = content_type

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Api
module V1
class CharactersController < Api::V1::ApiController
before_action :set
def show
render json: CharacterBlueprint.render(@character)
end
private
def set
@character = Character.where(granblue_id: params[:id]).first
end
end
end
end

View file

@ -7,7 +7,11 @@ module Api
before_action :find_party, only: :create
before_action :set, only: %i[update destroy]
<<<<<<< HEAD
before_action :check_authorization, only: %i[update destroy]
=======
before_action :authorize, only: %i[create update destroy]
>>>>>>> main
before_action :find_incoming_character, only: :create
before_action :find_current_characters, only: :create
@ -135,17 +139,33 @@ module Api
render_unauthorized_response if current_user && (party.user != current_user)
end
<<<<<<< HEAD
def check_authorization
render_unauthorized_response if @character.party.user != current_user
=======
def authorize
# Create
unauthorized_create = @party && (@party.user != current_user || @party.edit_key != edit_key)
unauthorized_update = @character && @character.party && (@character.party.user != current_user || @character.party.edit_key != edit_key)
render_unauthorized_response if unauthorized_create || unauthorized_update
>>>>>>> main
end
# Specify whitelisted properties that can be modified.
def character_params
params.require(:character).permit(:id, :party_id, :character_id, :position,
:uncap_level, :transcendence_step, :perpetuity,
<<<<<<< HEAD
ring1: %i[modifier strength], ring2: %i[modifier strength],
ring3: %i[modifier strength], ring4: %i[modifier strength],
earring: %i[modifier strength], awakening: %i[type level])
=======
:awakening_id, :awakening_level,
ring1: %i[modifier strength], ring2: %i[modifier strength],
ring3: %i[modifier strength], ring4: %i[modifier strength],
earring: %i[modifier strength])
>>>>>>> main
end
def resolve_params

View file

@ -3,12 +3,21 @@
module Api
module V1
class GridSummonsController < Api::V1::ApiController
<<<<<<< HEAD
before_action :set, only: %w[update destroy]
attr_reader :party, :incoming_summon
before_action :find_party, only: :create
before_action :find_incoming_summon, only: :create
=======
attr_reader :party, :incoming_summon
before_action :set, only: %w[update update_uncap_level update_quick_summon]
before_action :find_party, only: :create
before_action :find_incoming_summon, only: :create
before_action :authorize, only: %i[create update update_uncap_level update_quick_summon destroy]
>>>>>>> main
def create
# Create the GridSummon with the desired parameters
@ -24,10 +33,72 @@ module Api
def update
@summon.attributes = summon_params
<<<<<<< HEAD
return render json: GridSummonBlueprint.render(@summon, view: :nested, root: :grid_summon) if @summon.save
render_validation_error_response(@character)
=======
return render json: GridSummonBlueprint.render(@summon, view: :nested, root: :grid_summon) if @summon.save
render_validation_error_response(@character)
end
def update_uncap_level
summon = @summon.summon
max_uncap_level = if summon.flb && !summon.ulb && !summon.xlb
4
elsif summon.ulb && !summon.xlb
5
elsif summon.xlb
6
else
3
end
greater_than_max_uncap = summon_params[:uncap_level].to_i > max_uncap_level
can_be_transcended = summon.xlb && summon_params[:transcendence_step] && summon_params[:transcendence_step]&.to_i&.positive?
uncap_level = if greater_than_max_uncap || can_be_transcended
max_uncap_level
else
summon_params[:uncap_level]
end
transcendence_step = if summon.xlb && summon_params[:transcendence_step]
summon_params[:transcendence_step]
else
0
end
@summon.update!(
uncap_level: uncap_level,
transcendence_step: transcendence_step
)
return unless @summon.persisted?
render json: GridSummonBlueprint.render(@summon, view: :nested, root: :grid_summon)
end
def update_quick_summon
return if [4, 5, 6].include?(@summon.position)
quick_summons = @summon.party.summons.select(&:quick_summon)
quick_summons.each do |summon|
summon.update!(quick_summon: false)
end
@summon.update!(quick_summon: summon_params[:quick_summon])
return unless @summon.persisted?
quick_summons -= [@summon]
summons = [@summon] + quick_summons
render json: GridSummonBlueprint.render(summons, view: :nested, root: :summons)
>>>>>>> main
end
def save_summon(summon)
@ -42,6 +113,7 @@ module Api
output = render_grid_summon_view(summon)
render json: output, status: :created
<<<<<<< HEAD
end
def handle_conflict(summon)
@ -56,24 +128,39 @@ module Api
output = render_grid_summon_view(conflict_summon, old_position)
render json: output
=======
>>>>>>> main
end
def update_uncap_level
summon = GridSummon.find(summon_params[:id])
def handle_conflict(summon)
conflict_summon = summon.conflicts(party)
return unless conflict_summon.summon.id == incoming_summon.id
render_unauthorized_response if current_user && (summon.party.user != current_user)
old_position = conflict_summon.position
conflict_summon.position = summon_params[:position]
<<<<<<< HEAD
summon.uncap_level = summon_params[:uncap_level]
summon.transcendence_step = 0
return unless summon.save!
=======
return unless conflict_summon.save
>>>>>>> main
render json: GridSummonBlueprint.render(summon, view: :nested, root: :grid_summon)
output = render_grid_summon_view(conflict_summon, old_position)
render json: output
end
def destroy
<<<<<<< HEAD
render_unauthorized_response if @summon.party.user != current_user
return render json: GridSummonBlueprint.render(@summon, view: :destroyed) if @summon.destroy
=======
summon = GridSummon.find_by('id = ?', params[:id])
render_unauthorized_response if summon.party.user != current_user
return render json: GridSummonBlueprint.render(summon, view: :destroyed) if summon.destroy
>>>>>>> main
end
private
@ -90,18 +177,40 @@ module Api
def render_grid_summon_view(grid_summon, conflict_position = nil)
GridSummonBlueprint.render(grid_summon, view: :nested,
<<<<<<< HEAD
root: :grid_summon,
meta: { replaced: conflict_position })
end
def set
@summon = GridSummon.where('id = ?', params[:id]).first
=======
root: :grid_summon,
meta: { replaced: conflict_position })
end
def authorize
# Create
unauthorized_create = @party && (@party.user != current_user || @party.edit_key != edit_key)
unauthorized_update = @summon && @summon.party && (@summon.party.user != current_user || @summon.party.edit_key != edit_key)
render_unauthorized_response if unauthorized_create || unauthorized_update
end
def set
@summon = GridSummon.find_by('id = ?', summon_params[:id])
>>>>>>> main
end
# Specify whitelisted properties that can be modified.
def summon_params
<<<<<<< HEAD
params.require(:summon).permit(:id, :party_id, :summon_id, :position, :main, :friend, :uncap_level,
:transcendence_step)
=======
params.require(:summon).permit(:id, :party_id, :summon_id, :position, :main, :friend,
:quick_summon, :uncap_level, :transcendence_step)
>>>>>>> main
end
end
end

View file

@ -3,12 +3,17 @@
module Api
module V1
class GridWeaponsController < Api::V1::ApiController
<<<<<<< HEAD
before_action :set, except: %w[create update_uncap_level]
=======
>>>>>>> main
attr_reader :party, :incoming_weapon
before_action :set, except: %w[create update_uncap_level]
before_action :find_party, only: :create
before_action :find_incoming_weapon, only: :create
before_action :authorize, only: %i[create update destroy]
def create
# Create the GridWeapon with the desired parameters
@ -183,6 +188,14 @@ module Api
@weapon = GridWeapon.where('id = ?', params[:id]).first
end
def authorize
# Create
unauthorized_create = @party && (@party.user != current_user || @party.edit_key != edit_key)
unauthorized_update = @weapon && @weapon.party && (@weapon.party.user != current_user || @weapon.party.edit_key != edit_key)
render_unauthorized_response if unauthorized_create || unauthorized_update
end
# Specify whitelisted properties that can be modified.
def weapon_params
params.require(:weapon).permit(
@ -190,7 +203,7 @@ module Api
:position, :mainhand, :uncap_level, :element,
:weapon_key1_id, :weapon_key2_id, :weapon_key3_id,
:ax_modifier1, :ax_modifier2, :ax_strength1, :ax_strength2,
:awakening_type, :awakening_level
:awakening_id, :awakening_level
)
end

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Api
module V1
class GuidebooksController < Api::V1::ApiController
def all
render json: GuidebookBlueprint.render(Guidebook.all)
end
end
end
end

View file

@ -3,7 +3,8 @@
module Api
module V1
class JobsController < Api::V1::ApiController
before_action :set, only: %w[update_job update_job_skills]
before_action :set, only: %w[update_job update_job_skills destroy_job_skill]
before_action :authorize, only: %w[update_job update_job_skills destroy_job_skill]
def all
render json: JobBlueprint.render(Job.all)
@ -79,6 +80,12 @@ module Api
render json: PartyBlueprint.render(@party, view: :jobs) if @party.save!
end
def destroy_job_skill
position = job_params[:skill_position].to_i
@party["skill#{position}_id"] = nil
render json: PartyBlueprint.render(@party, view: :jobs) if @party.save
end
private
def merge_skills_with_existing_skills(
@ -149,7 +156,7 @@ module Api
def mismatched_skill(job, skill)
mismatched_main = (skill.job.id != job.id) && skill.main && !skill.sub
mismatched_emp = (skill.job.id != job.id) && skill.emp
mismatched_emp = (skill.job.id != job.id && skill.job.base_job.id != job.base_job.id) && skill.emp
mismatched_base = skill.job.base_job && (job.row != 'ex2' || skill.job.base_job.id != job.base_job.id) && skill.base
if %w[4 5 ex2].include?(job.row)
@ -165,6 +172,10 @@ module Api
end
end
def authorize
render_unauthorized_response if @party.user != current_user || @party.edit_key != edit_key
end
def set
@party = Party.where('id = ?', params[:id]).first
end
@ -175,7 +186,8 @@ module Api
:skill0_id,
:skill1_id,
:skill2_id,
:skill3_id
:skill3_id,
:skill_position
)
end
end

View file

@ -6,27 +6,25 @@ module Api
before_action :set_from_slug,
except: %w[create destroy update index favorites]
before_action :set, only: %w[update destroy]
before_action :authorize, only: %w[update destroy]
MAX_CHARACTERS = 5
MAX_SUMMONS = 8
MAX_WEAPONS = 13
DEFAULT_MIN_CHARACTERS = 3
DEFAULT_MIN_SUMMONS = 2
DEFAULT_MIN_WEAPONS = 5
DEFAULT_MAX_CLEAR_TIME = 5400
def create
party = Party.new
party.user = current_user if current_user
party.attributes = party_params if party_params
# unless party_params.empty?
# party.attributes = party_params
#
# # TODO: Extract this into a different method
# job = Job.find(party_params['job_id']) if party_params['job_id'].present?
# if job
# job_skills = JobSkill.where(job: job.id, main: true)
# job_skills.each_with_index do |skill, index|
# party["skill#{index}_id"] = skill.id
# end
# end
# end
if party.save!
return render json: PartyBlueprint.render(party, view: :full, root: :party),
return render json: PartyBlueprint.render(party, view: :created, root: :party),
status: :created
end
@ -40,19 +38,16 @@ module Api
end
def update
render_unauthorized_response if @party.user != current_user
@party.attributes = party_params.except(:skill1_id, :skill2_id, :skill3_id)
# TODO: Validate accessory with job
return render json: PartyBlueprint.render(@party, view: :full, root: :party) if @party.save!
return render json: PartyBlueprint.render(@party, view: :full, root: :party) if @party.save
render_validation_error_response(@party)
end
def destroy
render_unauthorized_response if @party.user != current_user
return render json: PartyBlueprint.render(@party, view: :destroyed, root: :checkin) if @party.destroy
end
@ -61,24 +56,30 @@ module Api
new_party.attributes = {
user: current_user,
name: remixed_name(@party.name),
source_party: @party
source_party: @party,
remix: true
}
new_party.local_id = party_params[:local_id] if !party_params.nil?
if new_party.save
render json: PartyBlueprint.render(new_party, view: :full, root: :party,
meta: { remix: true })
render json: PartyBlueprint.render(new_party, view: :created, root: :party),
status: :created
else
render_validation_error_response(new_party)
end
end
def index
conditions = build_conditions(request.params)
conditions = build_conditions
@parties = Party.joins(:weapons)
.group('parties.id')
.having('count(distinct grid_weapons.weapon_id) > 2')
.where(conditions)
.where(name_quality)
.where(user_quality)
.where(original)
.order(created_at: :desc)
.paginate(page: request.params[:page], per_page: COLLECTION_PER_PAGE)
.each { |party| party.favorited = current_user ? party.is_favorited(current_user) : false }
@ -99,11 +100,14 @@ module Api
def favorites
raise Api::V1::UnauthorizedError unless current_user
conditions = build_conditions(request.params)
conditions = build_conditions
conditions[:favorites] = { user_id: current_user.id }
@parties = Party.joins(:favorites)
.where(conditions)
.where(name_quality)
.where(user_quality)
.where(original)
.order('favorites.created_at DESC')
.paginate(page: request.params[:page], per_page: COLLECTION_PER_PAGE)
.each { |party| party.favorited = party.is_favorited(current_user) }
@ -123,20 +127,76 @@ module Api
private
def build_conditions(params)
def authorize
render_unauthorized_response if @party.user != current_user || @party.edit_key != edit_key
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|
hash[:element] = params['element'] unless params['element'].blank?
# 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?
hash[:weapons_count] = 5..13
# Advanced filters: Team parameters
hash[:full_auto] = params['full_auto'].to_i unless params['full_auto'].blank? || params['full_auto'].to_i == -1
hash[:auto_guard] = params['auto_guard'].to_i unless params['auto_guard'].blank? || params['auto_guard'].to_i == -1
hash[:charge_attack] = params['charge_attack'].to_i unless params['charge_attack'].blank? || params['charge_attack'].to_i == -1
# 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
"source_party_id IS NULL" unless request.params['original'].blank? || request.params['original'] == "false"
end
def user_quality
"user_id IS NOT NULL" unless request.params[:user_quality].blank? || request.params[:user_quality] == "false"
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(',')
"name NOT IN (#{joined_names})" unless request.params[:name_quality].blank? || request.params[:name_quality] == "false"
end
def remixed_name(name)
blanked_name = {
en: name.blank? ? 'Untitled team' : name,
@ -173,6 +233,8 @@ module Api
params.require(:party).permit(
:user_id,
:local_id,
:edit_key,
:extra,
:name,
:description,
@ -185,11 +247,15 @@ module Api
:skill3_id,
:full_auto,
:auto_guard,
:auto_summon,
:charge_attack,
:clear_time,
:button_count,
:turn_count,
:chain_count
:chain_count,
:guidebook1_id,
:guidebook2_id,
:guidebook3_id
)
end
end

View file

@ -4,7 +4,11 @@ module Api
module V1
class RaidsController < Api::V1::ApiController
def all
render json: RaidBlueprint.render(Raid.all)
render json: RaidBlueprint.render(Raid.all, view: :full)
end
def groups
render json: RaidGroupBlueprint.render(RaidGroup.all, view: :full)
end
end
end

View file

@ -3,6 +3,49 @@
module Api
module V1
class SearchController < Api::V1::ApiController
TRIGRAM = {
trigram: {
threshold: 0.3
}
}.freeze
TSEARCH_WITH_PREFIX = {
tsearch: {
prefix: true,
dictionary: 'simple'
}
}.freeze
def all
locale = search_params[:locale] || 'en'
case locale
when 'en'
results = search_all_en
when 'ja'
results = search_all_ja
end
render json: SearchBlueprint.render(results, root: :results)
end
def search_all_en
PgSearch.multisearch_options = { using: TRIGRAM }
results = PgSearch.multisearch(search_params[:query]).limit(10)
if (results.length < 5) && (search_params[:query].length >= 2)
PgSearch.multisearch_options = { using: TSEARCH_WITH_PREFIX }
results = PgSearch.multisearch(search_params[:query]).limit(10)
end
results
end
def search_all_ja
PgSearch.multisearch_options = { using: TSEARCH_WITH_PREFIX }
PgSearch.multisearch(search_params[:query]).limit(10)
end
def characters
filters = search_params[:filters]
locale = search_params[:locale] || 'en'
@ -24,7 +67,7 @@ module Api
characters = if search_params[:query].present? && search_params[:query].length >= 2
if locale == 'ja'
Character.jp_search(search_params[:query]).where(conditions)
Character.ja_search(search_params[:query]).where(conditions)
else
Character.en_search(search_params[:query]).where(conditions)
end
@ -62,7 +105,7 @@ module Api
weapons = if search_params[:query].present? && search_params[:query].length >= 2
if locale == 'ja'
Weapon.jp_search(search_params[:query]).where(conditions)
Weapon.ja_search(search_params[:query]).where(conditions)
else
Weapon.en_search(search_params[:query]).where(conditions)
end
@ -95,7 +138,7 @@ module Api
summons = if search_params[:query].present? && search_params[:query].length >= 2
if locale == 'ja'
Summon.jp_search(search_params[:query]).where(conditions)
Summon.ja_search(search_params[:query]).where(conditions)
else
Summon.en_search(search_params[:query]).where(conditions)
end
@ -140,17 +183,34 @@ module Api
# Perform the query
skills = if search_params[:query].present? && search_params[:query].length >= 2
JobSkill.method("#{locale}_search").call(search_params[:query])
JobSkill.joins(:job)
.method("#{locale}_search").call(search_params[:query])
.where(conditions)
.where(job: job.id, main: false)
.or(
JobSkill.method("#{locale}_search").call(search_params[:query])
JobSkill.joins(:job)
.method("#{locale}_search").call(search_params[:query])
.where(conditions)
.where(sub: true)
.where.not(job: job.id)
)
.or(
JobSkill.joins(:job)
.method("#{locale}_search").call(search_params[:query])
.where(conditions)
.where(job: { base_job: job.base_job.id }, emp: true)
.where.not(job: job.id)
)
.or(
JobSkill.joins(:job)
.method("#{locale}_search").call(search_params[:query])
.where(conditions)
.where(job: { base_job: job.base_job.id }, base: true)
.where.not(job: job.id)
)
else
JobSkill.all
.joins(:job)
.where(conditions)
.where(job: job.id, main: false)
.or(
@ -165,6 +225,13 @@ module Api
.where(job: job.base_job.id, base: true)
.where.not(job: job.id)
)
.or(
JobSkill.all
.where(conditions)
.joins(:job)
.where(job: { base_job: job.base_job.id }, emp: true)
.where.not(job: job.id)
)
end
count = skills.length
@ -179,6 +246,26 @@ module Api
})
end
def guidebooks
# Perform the query
books = if search_params[:query].present? && search_params[:query].length >= 2
Guidebook.method("#{locale}_search").call(search_params[:query])
else
Guidebook.all
end
count = books.length
paginated = books.paginate(page: search_params[:page], per_page: SEARCH_PER_PAGE)
render json: GuidebookBlueprint.render(paginated,
root: :results,
meta: {
count: count,
total_pages: total_pages(count),
per_page: SEARCH_PER_PAGE
})
end
private
def total_pages(count)

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Api
module V1
class SummonsController < Api::V1::ApiController
before_action :set
def show
render json: SummonBlueprint.render(@summon)
end
private
def set
@summon = Summon.where(granblue_id: params[:id]).first
end
end
end
end

View file

@ -8,6 +8,16 @@ module Api
before_action :set, except: %w[create check_email check_username]
before_action :set_by_id, only: %w[info update]
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)
@ -43,12 +53,14 @@ module Api
if @user.nil?
render_not_found_response('user')
else
conditions = build_conditions(request.params)
conditions = build_conditions
conditions[:user_id] = @user.id
parties = Party
.where(conditions)
.where(name_quality)
.where(user_quality)
.where(original)
.order(created_at: :desc)
.paginate(page: request.params[:page], per_page: COLLECTION_PER_PAGE)
.each do |party|
@ -81,26 +93,85 @@ module Api
private
def build_conditions(params)
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|
hash[:element] = params['element'] unless params['element'].blank?
# 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
hash[:full_auto] = params['full_auto'].to_i unless params['full_auto'].blank? || params['full_auto'].to_i == -1
hash[:auto_guard] = params['auto_guard'].to_i unless params['auto_guard'].blank? || params['auto_guard'].to_i == -1
hash[:charge_attack] = params['charge_attack'].to_i unless params['charge_attack'].blank? || params['charge_attack'].to_i == -1
# 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
unless params.key?('original') || params['original'].blank? || params['original'] == '0'
"source_party_id IS NULL"
end
end
def user_quality
unless params.key?('user_quality') || params[:user_quality].nil? || params[:user_quality] == "0"
"user_id IS NOT NULL"
end
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(',')
unless params.key?('name_quality') || params[:name_quality].nil? || params[:name_quality] == "0"
"name NOT IN (#{joined_names})"
end
end
# Specify whitelisted properties that can be modified.
def set
@user = User.where('username = ?', params[:id]).first
@user = User.find_by('lower(username) = ?', params[:id].downcase)
end
def set_by_id
@user = User.where('id = ?', params[:id]).first
@user = User.find_by('id = ?', params[:id])
end
def user_params

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Api
module V1
class WeaponsController < Api::V1::ApiController
before_action :set
def show
render json: WeaponBlueprint.render(@weapon)
end
private
def set
@weapon = Weapon.where(granblue_id: params[:id]).first
end
end
end
end

View file

@ -20,7 +20,6 @@ module Api
end
def to_hash
ap @data
{
message: message,
code: code,

15
app/models/awakening.rb Normal file
View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class Awakening < ApplicationRecord
def weapon_awakenings
WeaponAwakening.where(awakening_id: id)
end
def weapons
weapon_awakenings.map(&:weapon)
end
def awakening
AwakeningBlueprint
end
end

View file

@ -3,6 +3,16 @@
class Character < ApplicationRecord
include PgSearch::Model
multisearchable against: %i[name_en name_jp],
additional_attributes: lambda { |character|
{
name_en: character.name_en,
name_jp: character.name_jp,
granblue_id: character.granblue_id,
element: character.element
}
}
pg_search_scope :en_search,
against: :name_en,
using: {
@ -11,7 +21,7 @@ class Character < ApplicationRecord
}
}
pg_search_scope :jp_search,
pg_search_scope :ja_search,
against: :name_jp,
using: {
tsearch: {

2
app/models/gacha.rb Normal file
View file

@ -0,0 +1,2 @@
class Gacha < ApplicationRecord
end

View file

@ -1,12 +1,13 @@
# frozen_string_literal: true
class GridCharacter < ApplicationRecord
belongs_to :awakening, optional: true
belongs_to :party,
counter_cache: :characters_count,
inverse_of: :characters
validates_presence_of :party
validate :awakening_level, on: :update
validate :validate_awakening_level, on: :update
validate :transcendence, on: :update
validate :validate_over_mastery_values, on: :update
validate :validate_aetherial_mastery_value, on: :update
@ -22,11 +23,12 @@ class GridCharacter < ApplicationRecord
set perpetuity: false
end
def awakening_level
return if awakening.nil?
# Add awakening before the model saves
before_save :add_awakening
errors.add(:awakening, 'awakening level too low') if awakening['level'] < 1
errors.add(:awakening, 'awakening level too high') if awakening['level'] > 9
def validate_awakening_level
errors.add(:awakening, 'awakening level too low') if awakening_level < 1
errors.add(:awakening, 'awakening level too high') if awakening_level > 9
end
def transcendence
@ -84,6 +86,12 @@ class GridCharacter < ApplicationRecord
private
def add_awakening
if self.awakening.nil?
self.awakening = Awakening.where(slug: "character-balanced").sole
end
end
def check_value(property, type)
# Input format
# { ring1: { atk: 300 } }

View file

@ -10,9 +10,13 @@ class GridWeapon < ApplicationRecord
belongs_to :weapon_key2, class_name: 'WeaponKey', foreign_key: :weapon_key2_id, optional: true
belongs_to :weapon_key3, class_name: 'WeaponKey', foreign_key: :weapon_key3_id, optional: true
belongs_to :awakening, optional: true
validate :compatible_with_position, on: :create
validate :no_conflicts, on: :create
before_save :is_mainhand
##### Amoeba configuration
amoeba do
nullify :ax_modifier1
@ -71,4 +75,13 @@ class GridWeapon < ApplicationRecord
# Check if the grid weapon conflicts with any of the other grid weapons in the party
errors.add(:series, 'must not conflict with existing weapons') unless conflicts(party).nil?
end
# Checks if the weapon should be a mainhand before saving the model
def is_mainhand
if self.position == -1
self.mainhand = true
else
self.mainhand = false
end
end
end

37
app/models/guidebook.rb Normal file
View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
class Guidebook < ApplicationRecord
alias eql? ==
include PgSearch::Model
pg_search_scope :en_search,
against: :name_en,
using: {
tsearch: {
prefix: true,
dictionary: 'simple'
}
}
pg_search_scope :ja_search,
against: :name_jp,
using: {
tsearch: {
prefix: true,
dictionary: 'simple'
}
}
def blueprint
GuidebookBlueprint
end
def display_resource(book)
book.name_en
end
def ==(other)
self.class == other.class && granblue_id === other.granblue_id
end
end

View file

@ -1,7 +1,20 @@
# frozen_string_literal: true
class Job < ApplicationRecord
include PgSearch::Model
belongs_to :party
has_many :skills, class_name: 'JobSkill'
multisearchable against: %i[name_en name_jp],
additional_attributes: lambda { |job|
{
name_en: job.name_en,
name_jp: job.name_jp,
granblue_id: job.granblue_id,
element: 0
}
}
belongs_to :base_job,
foreign_key: 'base_job_id',

View file

@ -16,7 +16,7 @@ class JobSkill < ApplicationRecord
}
}
pg_search_scope :jp_search,
pg_search_scope :ja_search,
against: :name_jp,
using: {
tsearch: {

View file

@ -10,7 +10,8 @@ class Party < ApplicationRecord
has_many :derivative_parties,
class_name: 'Party',
foreign_key: :source_party_id,
inverse_of: :source_party
inverse_of: :source_party,
dependent: :nullify
belongs_to :user, optional: true
belongs_to :raid, optional: true
@ -41,6 +42,21 @@ class Party < ApplicationRecord
class_name: 'JobSkill',
optional: true
belongs_to :guidebook1,
foreign_key: 'guidebook1_id',
class_name: 'Guidebook',
optional: true
belongs_to :guidebook2,
foreign_key: 'guidebook2_id',
class_name: 'Guidebook',
optional: true
belongs_to :guidebook3,
foreign_key: 'guidebook3_id',
class_name: 'Guidebook',
optional: true
has_many :characters,
foreign_key: 'party_id',
class_name: 'GridCharacter',
@ -59,12 +75,17 @@ class Party < ApplicationRecord
dependent: :destroy,
inverse_of: :party
has_many :favorites
has_many :favorites, dependent: :destroy
before_create :set_shortcode
before_create :set_edit_key
##### Amoeba configuration
amoeba do
set weapons_count: 0
set characters_count: 0
set summons_count: 0
nullify :description
nullify :shortcode
@ -75,11 +96,12 @@ class Party < ApplicationRecord
##### ActiveRecord Validations
validate :skills_are_unique
validate :guidebooks_are_unique
attr_accessor :favorited
def is_favorited(user)
user.favorite_parties.include? self
user.favorite_parties.include? self if user
end
def is_remix
@ -100,6 +122,12 @@ class Party < ApplicationRecord
self.shortcode = random_string
end
def set_edit_key
if !self.user
self.edit_key = Digest::SHA1.hexdigest([Time.now, rand].join)
end
end
def random_string
num_chars = 6
o = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten
@ -119,4 +147,17 @@ class Party < ApplicationRecord
errors.add(:job_skills, 'must be unique')
end
def guidebooks_are_unique
guidebooks = [guidebook1, guidebook2, guidebook3].compact
return if guidebooks.uniq.length == guidebooks.length
guidebooks.each_with_index do |book, index|
next if index.zero?
errors.add(:"guidebook#{index + 1}", 'must be unique') if guidebooks[0...index].include?(book)
end
errors.add(:guidebooks, 'must be unique')
end
end

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true
class Raid < ApplicationRecord
belongs_to :group, class_name: 'RaidGroup', foreign_key: :group_id
def blueprint
RaidBlueprint
end

9
app/models/raid_group.rb Normal file
View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
class RaidGroup < ApplicationRecord
has_many :raids, class_name: 'Raid', foreign_key: :group_id
def blueprint
RaidGroupBlueprint
end
end

View file

@ -3,6 +3,16 @@
class Summon < ApplicationRecord
include PgSearch::Model
multisearchable against: %i[name_en name_jp],
additional_attributes: lambda { |summon|
{
name_en: summon.name_en,
name_jp: summon.name_jp,
granblue_id: summon.granblue_id,
element: summon.element
}
}
pg_search_scope :en_search,
against: :name_en,
using: {
@ -11,7 +21,7 @@ class Summon < ApplicationRecord
}
}
pg_search_scope :jp_search,
pg_search_scope :ja_search,
against: :name_jp,
using: {
tsearch: {

View file

@ -3,6 +3,16 @@
class Weapon < ApplicationRecord
include PgSearch::Model
multisearchable against: %i[name_en name_jp],
additional_attributes: lambda { |weapon|
{
name_en: weapon.name_en,
name_jp: weapon.name_jp,
granblue_id: weapon.granblue_id,
element: weapon.element
}
}
pg_search_scope :en_search,
against: :name_en,
using: {
@ -11,7 +21,7 @@ class Weapon < ApplicationRecord
}
}
pg_search_scope :jp_search,
pg_search_scope :ja_search,
against: :name_jp,
using: {
tsearch: {
@ -20,6 +30,9 @@ class Weapon < ApplicationRecord
}
}
has_many :weapon_awakenings
has_many :awakenings, through: :weapon_awakenings
def blueprint
WeaponBlueprint
end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
class WeaponAwakening < ApplicationRecord
belongs_to :weapon
belongs_to :awakening
def weapon
Weapon.find(weapon_id)
end
def awakening
Awakening.find(awakening_id)
end
end

27
bin/squasher Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'squasher' is installed as part of a gem, and
# this file is here to facilitate running it.
#
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("squasher", "squasher")

View file

@ -1 +1 @@
d2FydGGNzmcDxx3yD8kWlU7vquTJA/QHjPxZhjcoV65DZYU2JgRZSwL+zzE+Vl4bfXtkHKXhyI821y2DvcCtFpHPmNuUncmvmt+jq9mkrK1KuQts9FLshzw1JdCDioGr+JUmMmb55nPChtHUTnd+eW7BXi9KfBtogA9vDlkEG47epYKv0Wn99ziOP/fyvIPVC+nRtUePHQvDAqIENK7doHDKoDhNkhYbCNwH8Xa+F+kZNVKMgpyoCkNDPg10NyUhub7rHBEX41xGeluZVGAkG6HsBB1XNHAkyCQroBKh/XTHZ4brCTeaoJHL3W+/nwZrRDnBVWl7p6lh17JGgfmTzx/oNBqk/FJHR9lfAdkh/msrqpl5YlnsB9nY6vmjEEX4epylGYWDndoo0INYLawOZp1xFgQFedPb7ZU5--f6jX9dWlDgeyy6gd--nHpeshtZQBL1eBzNeocBoA==
Fxc8acnxWOFdt+zwWoACR/fskFH2+ZY5izq5cHf8pnGDKRSoI7QYm0h8RwevJtRUvUJQsJ+ja/xzbTYxNC4ABRSBe06lXwHJuCnt5YtR+4l+NiFnS76kGzSfhlfhmvPLtSdfTVRfhRib1vrz7E38jM1pcc2QBkzCxyaoZRu3X65U+gc7EqTjOsg8wpTjJwvfTXW9gkFNwFSen3nOSytewYDcivwUjr/3NUAONKHn4rNhBN3UJiNgOSCGj77Xx60E0Q95CidbkgExcyKAIMMsQgLKGhQRr9yUGxdshMuhA3JhVQSyvtd+jX8PmNX3FQusQIg7YUCh/WpiKo3aimZLQYY2n7lbfeSLpwuishjn138GAxe59Wgm1JhKN4xAkcAq54Q9d4AGFnu/IphMhv1TO03CqnwX1BbfY142--n8Fil7/q3W/SrENe--J31ORG+51iIo29fjiZU3Uw==

View file

@ -8,7 +8,7 @@
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
if Rails.env.production?
origins %w[app.granblue.team hensei-web-production.up.railway.app]
origins %w[granblue.team app.granblue.team hensei-web-production.up.railway.app]
else
origins %w[staging.granblue.team 127.0.0.1:1234]
end

View file

@ -3,12 +3,12 @@
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, "\\1en"
# inflect.singular /^(ox)en/i, "\\1"
# inflect.irregular "person", "people"
# inflect.uncountable %w( fish sheep )
# end
ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, "\\1en"
# inflect.singular /^(ox)en/i, "\\1"
# inflect.irregular "person", "people"
inflect.uncountable %w( gacha )
end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|

View file

@ -11,6 +11,9 @@ Rails.application.routes.draw do
resources :grid_weapons, only: %i[update destroy]
resources :grid_characters, only: %i[update destroy]
resources :grid_summons, only: %i[update destroy]
resources :weapons, only: :show
resources :characters, only: :show
resources :summons, only: :show
resources :favorites, only: [:create]
get 'version', to: 'api#version'
@ -23,14 +26,17 @@ Rails.application.routes.draw do
put 'parties/:id/jobs', to: 'jobs#update_job'
put 'parties/:id/job_skills', to: 'jobs#update_job_skills'
delete 'parties/:id/job_skills', to: 'jobs#destroy_job_skill'
post 'check/email', to: 'users#check_email'
post 'check/username', to: 'users#check_username'
post 'search', to: 'search#all'
post 'search/characters', to: 'search#characters'
post 'search/weapons', to: 'search#weapons'
post 'search/summons', to: 'search#summons'
post 'search/job_skills', to: 'search#job_skills'
post 'search/guidebooks', to: 'search#guidebooks'
get 'jobs', to: 'jobs#all'
@ -38,7 +44,10 @@ Rails.application.routes.draw do
get 'jobs/:id/skills', to: 'job_skills#job'
get 'jobs/:id/accessories', to: 'job_accessories#job'
get 'guidebooks', to: 'guidebooks#all'
get 'raids', to: 'raids#all'
get 'raids/groups', to: 'raids#groups'
get 'weapon_keys', to: 'weapon_keys#all'
post 'characters', to: 'grid_characters#create'
@ -53,6 +62,7 @@ Rails.application.routes.draw do
post 'summons', to: 'grid_summons#create'
post 'summons/update_uncap', to: 'grid_summons#update_uncap_level'
post 'summons/update_quick_summon', to: 'grid_summons#update_quick_summon'
delete 'summons', to: 'grid_summons#destroy'
delete 'favorites', to: 'favorites#destroy'

View file

@ -1,20 +0,0 @@
# frozen_string_literal: true
class MigrateAxTypeToAx < ActiveRecord::Migration[6.1]
def up
Weapon.all.each do |weapon|
if weapon.ax_type > 0
weapon.ax = true
elsif weapon.ax_type == 0
weapon.ax = false
weapon.ax_type = nil
end
weapon.save
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -1,21 +0,0 @@
# frozen_string_literal: true
class SetFlbToFalseOnSummons < ActiveRecord::Migration[6.1]
def up
Summon.all.each do |summon|
if summon.flb.nil?
summon.flb = false
summon.save
end
if summon.ulb.nil?
summon.ulb = false
summon.save
end
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
class MigrateAwakeningTypeToNewAwakeningType < ActiveRecord::Migration[7.0]
def up
GridWeapon.all.each do |weapon|
if weapon.awakening_type&.positive? && weapon.awakening_type <= 3
slug = if weapon.awakening_type == 1
'weapon-atk'
elsif weapon.awakening_type == 2
'weapon-def'
elsif weapon.awakening_type == 3
'weapon-special'
end
new_awakening = Awakening.find_by(slug: slug)
weapon.awakening_id = new_awakening.id
weapon.save!
end
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -0,0 +1,30 @@
# frozen_string_literal: true
class MigrateCharacterAwakeningTypeToNewAwakeningType < ActiveRecord::Migration[7.0]
def up
GridCharacter.all.each do |character|
slug = if character['awakening']['type'] == 0
'character-balanced'
elsif character['awakening']['type'] == 1
'character-atk'
elsif character['awakening']['type'] == 2
'character-def'
elsif character['awakening']['type'] == 3
'character-multi'
else
'character-balanced'
end
new_awakening = Awakening.find_by(slug: slug)
character.awakening_id = new_awakening.id
character.awakening_level = character['awakening']['level']
character.save!(validate: false)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class PopulateRemixFlagOnParties < ActiveRecord::Migration[7.0]
def up
Party.find_each do |party|
party.update(remix: party.source_party_id.present?)
end
end
def down
Party.find_each do |party|
party.update(remix: false)
end
end
end

View file

@ -1 +1 @@
DataMigrate::Data.define(version: 20230102235227)
DataMigrate::Data.define(version: 20230702035600)

View file

@ -1,5 +0,0 @@
class EnablePgcryptoExtension < ActiveRecord::Migration[5.0]
def change
enable_extension 'pgcrypto'
end
end

View file

@ -1,12 +0,0 @@
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :email, :unique => true
t.string :password_digest
t.string :username, :unique => true
t.integer :granblue_id, :unique => true
t.timestamps
end
end
end

View file

@ -1,28 +0,0 @@
class CreateWeapons < ActiveRecord::Migration[6.0]
def change
create_table :weapons, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name_en
t.string :name_jp
t.string :granblue_id
t.integer :rarity
t.integer :element
t.integer :proficiency
t.string :series
t.boolean :flb
t.boolean :ulb
t.integer :max_level
t.integer :max_skill_level
t.integer :min_hp
t.integer :max_hp
t.integer :max_hp_flb
t.integer :max_hp_ulb
t.integer :min_atk
t.integer :max_atk
t.integer :max_atk_flb
t.integer :max_atk_ulb
end
end
end

View file

@ -1,11 +0,0 @@
class CreateParties < ActiveRecord::Migration[6.0]
def change
create_table :parties, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.references :user, type: :uuid
t.string :shortcode
t.timestamps
end
end
end

View file

@ -1,17 +0,0 @@
class CreateGridWeapons < ActiveRecord::Migration[6.0]
def change
create_table :grid_weapons, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.references :party, type: :uuid
t.references :weapon, type: :uuid
t.references :weapon_key1, class_name: 'WeaponKey', type: :uuid
t.references :weapon_key2, class_name: 'WeaponKey', type: :uuid
t.integer :uncap_level
t.boolean :mainhand
t.integer :position
t.timestamps
end
end
end

View file

@ -1,13 +0,0 @@
class CreateWeaponKeys < ActiveRecord::Migration[6.0]
def change
create_table :weapon_keys, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name_en
t.string :name_jp
t.integer :series
t.integer :type
t.timestamps
end
end
end

View file

@ -1,70 +0,0 @@
# frozen_string_literal: true
class CreateDoorkeeperTables < ActiveRecord::Migration[6.0]
def change
create_table :oauth_applications, id: :uuid do |t|
t.string :name, null: false
t.string :uid, null: false
t.string :secret, null: false
t.text :redirect_uri, null: false
t.string :scopes, null: false, default: ''
t.timestamps null: false
end
add_index :oauth_applications, :uid, unique: true
create_table :oauth_access_grants, id: :uuid do |t|
t.uuid :resource_owner_id, null: false
t.uuid :application_id, null: false
t.string :token, null: false
t.integer :expires_in, null: false
t.text :redirect_uri, null: false
t.datetime :created_at, null: false
t.datetime :revoked_at
t.string :scopes
end
add_index :oauth_access_grants, :token, unique: true
add_foreign_key(
:oauth_access_grants,
:oauth_applications,
column: :application_id
)
create_table :oauth_access_tokens, id: :uuid do |t|
t.uuid :resource_owner_id
t.uuid :application_id
# If you use a custom token generator you may need to change this column
# from string to text, so that it accepts tokens larger than 255
# characters. More info on custom token generators in:
# https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator
#
# t.text :token, null: false
t.string :token, null: false
t.string :refresh_token
t.integer :expires_in
t.datetime :revoked_at
t.datetime :created_at, null: false
t.string :scopes
# If there is a previous_refresh_token column,
# refresh tokens will be revoked after a related access token is used.
# If there is no previous_refresh_token column,
# previous tokens are revoked as soon as a new access token is created.
# Comment out this line if you'd rather have refresh tokens
# instantly revoked.
t.string :previous_refresh_token, null: false, default: ""
end
add_index :oauth_access_tokens, :token, unique: true
add_index :oauth_access_tokens, :resource_owner_id
add_index :oauth_access_tokens, :refresh_token, unique: true
add_foreign_key(
:oauth_access_tokens,
:oauth_applications,
column: :application_id
)
end
end

View file

@ -1,26 +0,0 @@
class CreateSummons < ActiveRecord::Migration[6.0]
def change
create_table :summons, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name_en
t.string :name_jp
t.string :granblue_id
t.integer :rarity
t.integer :element
t.string :series
t.boolean :flb
t.boolean :ulb
t.integer :max_level
t.integer :min_hp
t.integer :max_hp
t.integer :max_hp_flb
t.integer :max_hp_ulb
t.integer :min_atk
t.integer :max_atk
t.integer :max_atk_flb
t.integer :max_atk_ulb
end
end
end

View file

@ -1,15 +0,0 @@
class CreateGridSummons < ActiveRecord::Migration[6.0]
def change
create_table :grid_summons, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.references :party, type: :uuid
t.references :summon, type: :uuid
t.integer :uncap_level
t.boolean :main
t.boolean :friend
t.integer :position
t.timestamps
end
end
end

View file

@ -1,32 +0,0 @@
class CreateCharacters < ActiveRecord::Migration[6.0]
def change
create_table :characters, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name_en
t.string :name_jp
t.string :granblue_id
t.integer :rarity
t.integer :element
t.integer :proficiency1
t.integer :proficiency2
t.integer :gender
t.integer :race1
t.integer :race2
t.boolean :flb
t.boolean :max_level
t.integer :min_hp
t.integer :max_hp
t.integer :max_hp_flb
t.integer :min_atk
t.integer :max_atk
t.integer :max_atk_flb
t.integer :base_da
t.integer :base_ta
t.float :ougi_ratio
t.float :ougi_ratio_flb
end
end
end

View file

@ -1,13 +0,0 @@
class CreateGridCharacters < ActiveRecord::Migration[6.0]
def change
create_table :grid_characters do |t|
t.references :party, type: :uuid
t.references :character, type: :uuid
t.integer :uncap_level
t.integer :position
t.timestamps
end
end
end

View file

@ -1,5 +0,0 @@
class AddExtraToParty < ActiveRecord::Migration[6.1]
def change
add_column :parties, :extra, :boolean, :default => false, :null => false
end
end

View file

@ -1,5 +0,0 @@
class AddExtraToWeapons < ActiveRecord::Migration[6.1]
def change
add_column :weapons, :extra, :boolean, :default => false, :null => false
end
end

View file

@ -1,5 +0,0 @@
class AddSubauraToSummons < ActiveRecord::Migration[6.1]
def change
add_column :summons, :subaura, :boolean, :default => false, :null => false
end
end

View file

@ -1,5 +0,0 @@
class AddLimitsToWeapons < ActiveRecord::Migration[6.1]
def change
add_column :weapons, :limit, :integer
end
end

View file

@ -1,5 +0,0 @@
class AddLimitsToSummons < ActiveRecord::Migration[6.1]
def change
add_column :summons, :limit, :integer
end
end

View file

@ -1,13 +0,0 @@
class AddDefaultToLbOnWeapons < ActiveRecord::Migration[6.1]
def change
def self.up
change_column :weapons, :flb, :boolean, default: false
change_column :weapons, :ulb, :boolean, default: false
end
def self.down
change_column :weapons, :flb, :boolean, default: nil
change_column :weapons, :ulb, :boolean, default: nil
end
end
end

View file

@ -1,5 +0,0 @@
class AddAxToWeapons < ActiveRecord::Migration[6.1]
def change
add_column :weapons, :ax, :integer
end
end

View file

@ -1,10 +0,0 @@
class AddSpecialToCharacters < ActiveRecord::Migration[6.1]
def up
add_column :characters, :special, :boolean, :default => false
change_column_null :characters, :special, false
end
def down
remove_column :characters, :special, :boolean
end
end

View file

@ -1,15 +0,0 @@
class AddUlbToCharacters < ActiveRecord::Migration[6.1]
def up
add_column :characters, :ulb, :boolean, :default => false
add_column :characters, :max_hp_ulb, :integer
add_column :characters, :max_atk_ulb, :integer
change_column_null :characters, :ulb, false
change_column_null :characters, :flb, false
end
def down
remove_column :characters, :ulb, :boolean
remove_column :characters, :max_hp_ulb, :integer
remove_column :characters, :max_atk_ulb, :integer
end
end

View file

@ -1,5 +0,0 @@
class RemoveMaxLevelFromCharacters < ActiveRecord::Migration[6.1]
def change
remove_column :characters, :max_level, :boolean
end
end

View file

@ -1,5 +0,0 @@
class AddUuidToGridCharacter < ActiveRecord::Migration[6.1]
def change
add_column :grid_characters, :uuid, :uuid, default: "gen_random_uuid()", null: false
end
end

View file

@ -1,10 +0,0 @@
class ChangeGridCharacterIdToUuid < ActiveRecord::Migration[6.1]
def change
change_table :grid_characters do |t|
t.remove :id
t.rename :uuid, :id
end
execute "ALTER TABLE grid_characters ADD PRIMARY KEY (id);"
end
end

View file

@ -1,13 +0,0 @@
class AddDetailsToParty < ActiveRecord::Migration[6.1]
def change
create_table :raids, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name_en
t.string :name_jp
t.integer :level
end
add_column :parties, :name, :string
add_column :parties, :description, :text
add_reference :parties, :raids, index: true
end
end

View file

@ -1,5 +0,0 @@
class AddGroupToRaids < ActiveRecord::Migration[6.1]
def change
add_column :raids, :group, :integer
end
end

View file

@ -1,6 +0,0 @@
class FixRaidAssociationOnParties < ActiveRecord::Migration[6.1]
def change
add_column :parties, :raid_id, :uuid
remove_column :parties, :raids_id, :bigint
end
end

View file

@ -1,5 +0,0 @@
class AddElementToRaids < ActiveRecord::Migration[6.1]
def change
add_column :raids, :element, :integer
end
end

View file

@ -1,5 +0,0 @@
class AddElementToParties < ActiveRecord::Migration[6.1]
def change
add_column :parties, :element, :integer
end
end

View file

@ -1,9 +0,0 @@
class CreateFavorites < ActiveRecord::Migration[6.1]
def change
create_table :favorites, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.references :user, type: :uuid
t.references :party, type: :uuid
t.timestamps
end
end
end

View file

@ -1,5 +0,0 @@
class ChangeWeaponSeriesToNumber < ActiveRecord::Migration[6.1]
def change
change_column :weapons, :series, 'integer USING CAST(element AS integer)'
end
end

View file

@ -1,6 +0,0 @@
class RemoveTimestampsFromWeaponKeys < ActiveRecord::Migration[6.1]
def change
remove_column :weapon_keys, :created_at, :datetime
remove_column :weapon_keys, :updated_at, :datetime
end
end

View file

@ -1,5 +0,0 @@
class AddSubTypeToWeaponKeys < ActiveRecord::Migration[6.1]
def change
add_column :weapon_keys, :subtype, :integer
end
end

View file

@ -1,5 +0,0 @@
class AddWeaponKey3ToGridWeapons < ActiveRecord::Migration[6.1]
def change
add_reference :grid_weapons, :weapon_key3, type: :uuid, foreign_key: { to_table: :weapon_keys }
end
end

View file

@ -1,8 +0,0 @@
class AddAxToGridWeapons < ActiveRecord::Migration[6.1]
def change
add_column :grid_weapons, :ax_modifier1, :integer
add_column :grid_weapons, :ax_strength1, :float
add_column :grid_weapons, :ax_modifier2, :integer
add_column :grid_weapons, :ax_strength2, :float
end
end

View file

@ -1,5 +0,0 @@
class AddElementToGridWeapons < ActiveRecord::Migration[6.1]
def change
add_column :grid_weapons, :element, :integer
end
end

View file

@ -1,5 +0,0 @@
class AddPerpetuityToGridCharacters < ActiveRecord::Migration[6.1]
def change
add_column :grid_characters, :perpetuity, :boolean
end
end

View file

@ -1,6 +0,0 @@
class RenameTypeAndSubTypeInWeaponKeys < ActiveRecord::Migration[6.1]
def change
rename_column :weapon_keys, :type, :slot
rename_column :weapon_keys, :subtype, :group
end
end

View file

@ -1,5 +0,0 @@
class AddOrderToWeaponKeys < ActiveRecord::Migration[6.1]
def change
add_column :weapon_keys, :order, :integer
end
end

View file

@ -1,7 +0,0 @@
class AddFieldsToUser < ActiveRecord::Migration[6.1]
def change
add_column :users, :picture, :string
add_column :users, :language, :string
add_column :users, :private, :boolean
end
end

View file

@ -1,7 +0,0 @@
class AddDefaultValuesToUser < ActiveRecord::Migration[6.1]
def change
change_column :users, :picture, :string, :default => "gran"
change_column :users, :language, :string, :default => "en"
change_column :users, :private, :boolean, :default => false
end
end

View file

@ -1,6 +0,0 @@
class AddNotNullableToUser < ActiveRecord::Migration[6.1]
def change
change_column :users, :language, :string, :default => "en", :null => false
change_column :users, :private, :boolean, :default => false, :null => false
end
end

View file

@ -1,5 +0,0 @@
class AddElementToUser < ActiveRecord::Migration[6.1]
def change
add_column :users, :element, :string, :default => "water", :null => false
end
end

View file

@ -1,5 +0,0 @@
class AddSlugToRaids < ActiveRecord::Migration[6.1]
def change
add_column :raids, :slug, :string
end
end

View file

@ -1,7 +0,0 @@
class AddGinIndexToWeapons < ActiveRecord::Migration[6.1]
def change
enable_extension "pg_trgm"
enable_extension "btree_gin"
add_index :weapons, :name_en, using: :gin, opclass: :gin_trgm_ops
end
end

View file

@ -1,6 +0,0 @@
class AddGinIndexToSummonsAndCharacters < ActiveRecord::Migration[6.1]
def change
add_index :summons, :name_en, using: :gin, opclass: :gin_trgm_ops
add_index :characters, :name_en, using: :gin, opclass: :gin_trgm_ops
end
end

Some files were not shown because too many files have changed in this diff Show more