From 24b15c0740d80b9c0206d4ee6cfa71977cf1c14b Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 07:03:09 -0800 Subject: [PATCH 01/13] Add amoeba gem for cloning ActiveRecord objects --- Gemfile | 3 +++ Gemfile.lock | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Gemfile b/Gemfile index 3565c3f..66eeb1b 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,9 @@ gem 'will_paginate', '~> 3.3' # Migrate and update data alongside your database structure. gem 'data_migrate' +# A ruby gem to allow the copying of ActiveRecord objects and their associated children, configurable with a DSL on the model +gem 'amoeba' + group :doc do gem 'apipie-rails' gem 'sdoc' diff --git a/Gemfile.lock b/Gemfile.lock index 62087bc..a982265 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,6 +67,8 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) amazing_print (1.4.0) + amoeba (3.2.0) + activerecord (>= 4.2.0) api_matchers (0.6.2) activesupport (>= 3.2.5) nokogiri (>= 1.5.2) @@ -305,6 +307,7 @@ PLATFORMS DEPENDENCIES amazing_print + amoeba api_matchers apipie-rails awesome_nested_set From 70bbd476061bbb48a589e289ddf01c6c6408bc9b Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 07:03:24 -0800 Subject: [PATCH 02/13] Add endpoint and stub method --- app/controllers/api/v1/parties_controller.rb | 3 +++ config/routes.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index 258de6a..ff4ea0b 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -57,6 +57,9 @@ module Api return render json: PartyBlueprint.render(@party, view: :destroyed, root: :checkin) if @party.destroy end + def remix + end + def index conditions = build_conditions(request.params) diff --git a/config/routes.rb b/config/routes.rb index 8256840..ee59a61 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,7 @@ Rails.application.routes.draw do get 'parties/favorites', to: 'parties#favorites' get 'parties/:id', to: 'parties#show' + post 'parties/:id/remix', to: 'parties#remix' put 'parties/:id/jobs', to: 'jobs#update_job' put 'parties/:id/job_skills', to: 'jobs#update_job_skills' From c2576973bb6e96a7924098123452b0b176b83abe Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 19:03:25 -0800 Subject: [PATCH 03/13] Add source party column to parties --- ...30108150956_add_source_party_to_parties.rb | 7 + db/schema.rb | 541 +++++++++--------- 2 files changed, 279 insertions(+), 269 deletions(-) create mode 100644 db/migrate/20230108150956_add_source_party_to_parties.rb diff --git a/db/migrate/20230108150956_add_source_party_to_parties.rb b/db/migrate/20230108150956_add_source_party_to_parties.rb new file mode 100644 index 0000000..f2e4071 --- /dev/null +++ b/db/migrate/20230108150956_add_source_party_to_parties.rb @@ -0,0 +1,7 @@ +class AddSourcePartyToParties < ActiveRecord::Migration[7.0] + def change + change_table(:parties) do |t| + t.references :source_party, type: :uuid, foreign_key: { to_table: 'parties' } + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 4cea1cb..7cfa3d0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,309 +10,312 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_01_07_153724) do +ActiveRecord::Schema[7.0].define(version: 20_230_108_150_956) do # These are extensions that must be enabled in order to support this database - enable_extension "btree_gin" - enable_extension "pg_trgm" - enable_extension "pgcrypto" - enable_extension "plpgsql" + enable_extension 'btree_gin' + enable_extension 'pg_trgm' + enable_extension 'pgcrypto' + enable_extension 'plpgsql' - create_table "characters", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade 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", default: false, null: false - 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" - t.boolean "special", default: false, null: false - t.boolean "ulb", default: false, null: false - t.integer "max_hp_ulb" - t.integer "max_atk_ulb" - t.integer "character_id", default: [], null: false, array: true - t.index ["name_en"], name: "index_characters_on_name_en", opclass: :gin_trgm_ops, using: :gin + create_table 'characters', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade 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', default: false, null: false + 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' + t.boolean 'special', default: false, null: false + t.boolean 'ulb', default: false, null: false + t.integer 'max_hp_ulb' + t.integer 'max_atk_ulb' + t.integer 'character_id', default: [], null: false, array: true + t.index ['name_en'], name: 'index_characters_on_name_en', opclass: :gin_trgm_ops, using: :gin end - create_table "data_migrations", primary_key: "version", id: :string, force: :cascade do |t| + create_table 'data_migrations', primary_key: 'version', id: :string, force: :cascade do |t| end - create_table "favorites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "user_id" - t.uuid "party_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["party_id"], name: "index_favorites_on_party_id" - t.index ["user_id"], name: "index_favorites_on_user_id" + create_table 'favorites', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'user_id' + t.uuid 'party_id' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['party_id'], name: 'index_favorites_on_party_id' + t.index ['user_id'], name: 'index_favorites_on_user_id' end - create_table "grid_characters", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "party_id" - t.uuid "character_id" - t.integer "uncap_level" - t.integer "position" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "perpetuity", default: false, null: false - t.integer "transcendence_step", default: 0, null: false - t.jsonb "ring1", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.jsonb "ring2", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.jsonb "ring3", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.jsonb "ring4", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.jsonb "earring", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.jsonb "awakening", default: {"type"=>1, "level"=>1}, null: false - t.index ["character_id"], name: "index_grid_characters_on_character_id" - t.index ["party_id"], name: "index_grid_characters_on_party_id" + create_table 'grid_characters', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'party_id' + t.uuid 'character_id' + t.integer 'uncap_level' + t.integer 'position' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.boolean 'perpetuity', default: false, null: false + t.integer 'transcendence_step', default: 0, null: false + t.jsonb 'ring1', default: { 'modifier' => nil, 'strength' => nil }, null: false + t.jsonb 'ring2', default: { 'modifier' => nil, 'strength' => nil }, null: false + t.jsonb 'ring3', default: { 'modifier' => nil, 'strength' => nil }, null: false + t.jsonb 'ring4', default: { 'modifier' => nil, 'strength' => nil }, null: false + t.jsonb 'earring', default: { 'modifier' => nil, 'strength' => nil }, null: false + t.jsonb 'awakening', default: { 'type' => 1, 'level' => 1 }, null: false + t.index ['character_id'], name: 'index_grid_characters_on_character_id' + t.index ['party_id'], name: 'index_grid_characters_on_party_id' end - create_table "grid_summons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "party_id" - t.uuid "summon_id" - t.integer "uncap_level" - t.boolean "main" - t.boolean "friend" - t.integer "position" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "transcendence_step", default: 0, null: false - t.index ["party_id"], name: "index_grid_summons_on_party_id" - t.index ["summon_id"], name: "index_grid_summons_on_summon_id" + create_table 'grid_summons', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'party_id' + t.uuid 'summon_id' + t.integer 'uncap_level' + t.boolean 'main' + t.boolean 'friend' + t.integer 'position' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.integer 'transcendence_step', default: 0, null: false + t.index ['party_id'], name: 'index_grid_summons_on_party_id' + t.index ['summon_id'], name: 'index_grid_summons_on_summon_id' end - create_table "grid_weapons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "party_id" - t.uuid "weapon_id" - t.uuid "weapon_key1_id" - t.uuid "weapon_key2_id" - t.integer "uncap_level" - t.boolean "mainhand" - t.integer "position" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.uuid "weapon_key3_id" - t.integer "ax_modifier1" - t.float "ax_strength1" - t.integer "ax_modifier2" - t.float "ax_strength2" - t.integer "element" - t.integer "awakening_type" - t.integer "awakening_level", default: 1, null: false - t.index ["party_id"], name: "index_grid_weapons_on_party_id" - t.index ["weapon_id"], name: "index_grid_weapons_on_weapon_id" + create_table 'grid_weapons', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'party_id' + t.uuid 'weapon_id' + t.uuid 'weapon_key1_id' + t.uuid 'weapon_key2_id' + t.integer 'uncap_level' + t.boolean 'mainhand' + t.integer 'position' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.uuid 'weapon_key3_id' + t.integer 'ax_modifier1' + t.float 'ax_strength1' + t.integer 'ax_modifier2' + t.float 'ax_strength2' + t.integer 'element' + t.integer 'awakening_type' + t.integer 'awakening_level', default: 1, null: false + t.index ['party_id'], name: 'index_grid_weapons_on_party_id' + t.index ['weapon_id'], name: 'index_grid_weapons_on_weapon_id' end - create_table "job_skills", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "job_id" - t.string "name_en", null: false - t.string "name_jp", null: false - t.string "slug", null: false - t.integer "color", null: false - t.boolean "main", default: false - t.boolean "sub", default: false - t.boolean "emp", default: false - t.integer "order" - t.boolean "base", default: false - t.index ["job_id"], name: "index_job_skills_on_job_id" + create_table 'job_skills', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'job_id' + t.string 'name_en', null: false + t.string 'name_jp', null: false + t.string 'slug', null: false + t.integer 'color', null: false + t.boolean 'main', default: false + t.boolean 'sub', default: false + t.boolean 'emp', default: false + t.integer 'order' + t.boolean 'base', default: false + t.index ['job_id'], name: 'index_job_skills_on_job_id' end - create_table "jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name_en" - t.string "name_jp" - t.integer "proficiency1" - t.integer "proficiency2" - t.string "row" - t.boolean "ml", default: false - t.integer "order" - t.uuid "base_job_id" - t.index ["base_job_id"], name: "index_jobs_on_base_job_id" + create_table 'jobs', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.string 'name_en' + t.string 'name_jp' + t.integer 'proficiency1' + t.integer 'proficiency2' + t.string 'row' + t.boolean 'ml', default: false + t.integer 'order' + t.uuid 'base_job_id' + t.index ['base_job_id'], name: 'index_jobs_on_base_job_id' end - create_table "oauth_access_grants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade 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", precision: nil, null: false - t.datetime "revoked_at", precision: nil - t.string "scopes" - t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true + create_table 'oauth_access_grants', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade 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', precision: nil, null: false + t.datetime 'revoked_at', precision: nil + t.string 'scopes' + t.index ['token'], name: 'index_oauth_access_grants_on_token', unique: true end - create_table "oauth_access_tokens", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "resource_owner_id" - t.uuid "application_id" - t.string "token", null: false - t.string "refresh_token" - t.integer "expires_in" - t.datetime "revoked_at", precision: nil - t.datetime "created_at", precision: nil, null: false - t.string "scopes" - t.string "previous_refresh_token", default: "", null: false - t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true - t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id" - t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true + create_table 'oauth_access_tokens', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'resource_owner_id' + t.uuid 'application_id' + t.string 'token', null: false + t.string 'refresh_token' + t.integer 'expires_in' + t.datetime 'revoked_at', precision: nil + t.datetime 'created_at', precision: nil, null: false + t.string 'scopes' + t.string 'previous_refresh_token', default: '', null: false + t.index ['refresh_token'], name: 'index_oauth_access_tokens_on_refresh_token', unique: true + t.index ['resource_owner_id'], name: 'index_oauth_access_tokens_on_resource_owner_id' + t.index ['token'], name: 'index_oauth_access_tokens_on_token', unique: true end - create_table "oauth_applications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade 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", default: "", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true + create_table 'oauth_applications', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade 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', default: '', null: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['uid'], name: 'index_oauth_applications_on_uid', unique: true end - create_table "parties", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "user_id" - t.string "shortcode" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "extra", default: false, null: false - t.string "name" - t.text "description" - t.uuid "raid_id" - t.integer "element" - t.integer "weapons_count" - t.uuid "job_id" - t.integer "ml" - t.uuid "skill1_id" - t.uuid "skill2_id" - t.uuid "skill3_id" - t.uuid "skill0_id" - t.boolean "full_auto", default: false, null: false - t.boolean "auto_guard", default: false, null: false - t.boolean "charge_attack", default: true, null: false - t.integer "clear_time", default: 0, null: false - t.integer "button_count" - t.integer "chain_count" - t.integer "turn_count" - t.index ["job_id"], name: "index_parties_on_job_id" - t.index ["skill0_id"], name: "index_parties_on_skill0_id" - t.index ["skill1_id"], name: "index_parties_on_skill1_id" - t.index ["skill2_id"], name: "index_parties_on_skill2_id" - t.index ["skill3_id"], name: "index_parties_on_skill3_id" - t.index ["user_id"], name: "index_parties_on_user_id" + create_table 'parties', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.uuid 'user_id' + t.string 'shortcode' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.boolean 'extra', default: false, null: false + t.string 'name' + t.text 'description' + t.uuid 'raid_id' + t.integer 'element' + t.integer 'weapons_count' + t.uuid 'job_id' + t.integer 'ml' + t.uuid 'skill1_id' + t.uuid 'skill2_id' + t.uuid 'skill3_id' + t.uuid 'skill0_id' + t.boolean 'full_auto', default: false, null: false + t.boolean 'auto_guard', default: false, null: false + t.boolean 'charge_attack', default: true, null: false + t.integer 'clear_time', default: 0, null: false + t.integer 'button_count' + t.integer 'chain_count' + t.integer 'turn_count' + t.uuid 'source_party_id' + t.index ['job_id'], name: 'index_parties_on_job_id' + t.index ['skill0_id'], name: 'index_parties_on_skill0_id' + t.index ['skill1_id'], name: 'index_parties_on_skill1_id' + t.index ['skill2_id'], name: 'index_parties_on_skill2_id' + t.index ['skill3_id'], name: 'index_parties_on_skill3_id' + t.index ['source_party_id'], name: 'index_parties_on_source_party_id' + t.index ['user_id'], name: 'index_parties_on_user_id' end - create_table "raids", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name_en" - t.string "name_jp" - t.integer "level" - t.integer "group" - t.integer "element" - t.string "slug" + create_table 'raids', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.string 'name_en' + t.string 'name_jp' + t.integer 'level' + t.integer 'group' + t.integer 'element' + t.string 'slug' end - create_table "summons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade 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", default: false, null: false - t.boolean "ulb", default: false, null: false - t.integer "max_level", default: 100, null: false - 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" - t.boolean "subaura", default: false, null: false - t.boolean "limit", default: false, null: false - t.boolean "xlb", default: false, null: false - t.index ["name_en"], name: "index_summons_on_name_en", opclass: :gin_trgm_ops, using: :gin + create_table 'summons', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade 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', default: false, null: false + t.boolean 'ulb', default: false, null: false + t.integer 'max_level', default: 100, null: false + 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' + t.boolean 'subaura', default: false, null: false + t.boolean 'limit', default: false, null: false + t.boolean 'xlb', default: false, null: false + t.index ['name_en'], name: 'index_summons_on_name_en', opclass: :gin_trgm_ops, using: :gin end - create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "email" - t.string "password_digest" - t.string "username" - t.integer "granblue_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "picture", default: "gran" - t.string "language", default: "en", null: false - t.boolean "private", default: false, null: false - t.string "element", default: "water", null: false - t.integer "gender", default: 0, null: false - t.string "theme", default: "system", null: false + create_table 'users', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.string 'email' + t.string 'password_digest' + t.string 'username' + t.integer 'granblue_id' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.string 'picture', default: 'gran' + t.string 'language', default: 'en', null: false + t.boolean 'private', default: false, null: false + t.string 'element', default: 'water', null: false + t.integer 'gender', default: 0, null: false + t.string 'theme', default: 'system', null: false end - create_table "weapon_keys", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name_en" - t.string "name_jp" - t.integer "series" - t.integer "slot" - t.integer "group" - t.integer "order" - t.string "slug" + create_table 'weapon_keys', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.string 'name_en' + t.string 'name_jp' + t.integer 'series' + t.integer 'slot' + t.integer 'group' + t.integer 'order' + t.string 'slug' end - create_table "weapons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name_en" - t.string "name_jp" - t.string "granblue_id" - t.integer "rarity" - t.integer "element" - t.integer "proficiency" - t.integer "series", default: -1, null: false - t.boolean "flb", default: false, null: false - t.boolean "ulb", default: false, null: false - t.integer "max_level", default: 100, null: false - t.integer "max_skill_level", default: 10, null: false - 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" - t.boolean "extra", default: false, null: false - t.integer "ax_type" - t.boolean "awakening", default: true, null: false - t.boolean "limit", default: false, null: false - t.boolean "ax", default: false, null: false - t.index ["name_en"], name: "index_weapons_on_name_en", opclass: :gin_trgm_ops, using: :gin + create_table 'weapons', id: :uuid, default: -> { 'gen_random_uuid()' }, force: :cascade do |t| + t.string 'name_en' + t.string 'name_jp' + t.string 'granblue_id' + t.integer 'rarity' + t.integer 'element' + t.integer 'proficiency' + t.integer 'series', default: -1, null: false + t.boolean 'flb', default: false, null: false + t.boolean 'ulb', default: false, null: false + t.integer 'max_level', default: 100, null: false + t.integer 'max_skill_level', default: 10, null: false + 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' + t.boolean 'extra', default: false, null: false + t.integer 'ax_type' + t.boolean 'awakening', default: true, null: false + t.boolean 'limit', default: false, null: false + t.boolean 'ax', default: false, null: false + t.index ['name_en'], name: 'index_weapons_on_name_en', opclass: :gin_trgm_ops, using: :gin end - add_foreign_key "favorites", "parties" - add_foreign_key "favorites", "users" - add_foreign_key "grid_characters", "characters" - add_foreign_key "grid_characters", "parties" - add_foreign_key "grid_summons", "parties" - add_foreign_key "grid_summons", "summons" - add_foreign_key "grid_weapons", "parties" - add_foreign_key "grid_weapons", "weapon_keys", column: "weapon_key3_id" - add_foreign_key "grid_weapons", "weapons" - add_foreign_key "jobs", "jobs", column: "base_job_id" - add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id" - add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id" - add_foreign_key "parties", "job_skills", column: "skill0_id" - add_foreign_key "parties", "job_skills", column: "skill1_id" - add_foreign_key "parties", "job_skills", column: "skill2_id" - add_foreign_key "parties", "job_skills", column: "skill3_id" - add_foreign_key "parties", "jobs" - add_foreign_key "parties", "raids" - add_foreign_key "parties", "users" + add_foreign_key 'favorites', 'parties' + add_foreign_key 'favorites', 'users' + add_foreign_key 'grid_characters', 'characters' + add_foreign_key 'grid_characters', 'parties' + add_foreign_key 'grid_summons', 'parties' + add_foreign_key 'grid_summons', 'summons' + add_foreign_key 'grid_weapons', 'parties' + add_foreign_key 'grid_weapons', 'weapon_keys', column: 'weapon_key3_id' + add_foreign_key 'grid_weapons', 'weapons' + add_foreign_key 'jobs', 'jobs', column: 'base_job_id' + add_foreign_key 'oauth_access_grants', 'oauth_applications', column: 'application_id' + add_foreign_key 'oauth_access_tokens', 'oauth_applications', column: 'application_id' + add_foreign_key 'parties', 'job_skills', column: 'skill0_id' + add_foreign_key 'parties', 'job_skills', column: 'skill1_id' + add_foreign_key 'parties', 'job_skills', column: 'skill2_id' + add_foreign_key 'parties', 'job_skills', column: 'skill3_id' + add_foreign_key 'parties', 'jobs' + add_foreign_key 'parties', 'parties', column: 'source_party_id' + add_foreign_key 'parties', 'raids' + add_foreign_key 'parties', 'users' end From 2a465aca3ba5bc0be458c792e8e775a4e1e30c84 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 20:13:09 -0800 Subject: [PATCH 04/13] Move shortcode setting to before_save on Party model --- app/controllers/api/v1/parties_controller.rb | 13 +------------ app/models/party.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index ff4ea0b..f5171d8 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -8,12 +8,7 @@ module Api before_action :set, only: %w[update destroy] def create - party = Party.new(shortcode: random_string) - party.user = current_user if current_user - - if party_params - party.attributes = party_params - end + party = Party.new(party_params.merge(user: current_user)) # unless party_params.empty? # party.attributes = party_params @@ -125,12 +120,6 @@ module Api end end - def random_string - num_chars = 6 - o = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten - (0...num_chars).map { o[rand(o.length)] }.join - end - def set_from_slug @party = Party.where('shortcode = ?', params[:id]).first @party.favorited = current_user && @party ? @party.is_favorited(current_user) : false diff --git a/app/models/party.rb b/app/models/party.rb index e9840ff..b8066d0 100644 --- a/app/models/party.rb +++ b/app/models/party.rb @@ -43,6 +43,7 @@ class Party < ApplicationRecord has_many :favorites + before_save :set_shortcode ##### ActiveRecord Validations validate :skills_are_unique @@ -58,6 +59,16 @@ class Party < ApplicationRecord private + def set_shortcode + self.shortcode = random_string + end + + def random_string + num_chars = 6 + o = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten + (0...num_chars).map { o[rand(o.length)] }.join + end + def skills_are_unique skills = [skill0, skill1, skill2, skill3].compact From 433bd19f6de8cce3b18b4ccc163a18ed8a281486 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:45:31 -0800 Subject: [PATCH 05/13] Fix party creation --- app/controllers/api/v1/parties_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index f5171d8..cb03cc9 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -8,7 +8,9 @@ module Api before_action :set, only: %w[update destroy] def create - party = Party.new(party_params.merge(user: current_user)) + 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 From b0b446aba37b616ecedb9d2450c9b8f629036440 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:46:16 -0800 Subject: [PATCH 06/13] Fix set_from_slug --- app/controllers/api/v1/parties_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index cb03cc9..9ac5de4 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -124,7 +124,11 @@ module Api def set_from_slug @party = Party.where('shortcode = ?', params[:id]).first - @party.favorited = current_user && @party ? @party.is_favorited(current_user) : false + if @party + @party.favorited = current_user && @party ? @party.is_favorited(current_user) : false + else + render_not_found_response('party') + end end def set From 1925678888fff15847f1fdd9dec8729bde28a5e5 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:46:32 -0800 Subject: [PATCH 07/13] Return when no params --- app/controllers/api/v1/parties_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index 9ac5de4..5db36d6 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -136,6 +136,8 @@ module Api end def party_params + return unless params[:party].present? + params.require(:party).permit( :user_id, :extra, @@ -154,7 +156,7 @@ module Api :button_count, :turn_count, :chain_count - ) if params[:party].present? + ) end end end From a3e76d53e7f76c05b6678c55dab8274c30e1f3d9 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:48:10 -0800 Subject: [PATCH 08/13] Add amoeba configuration to Party --- app/models/party.rb | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/models/party.rb b/app/models/party.rb index b8066d0..40330d8 100644 --- a/app/models/party.rb +++ b/app/models/party.rb @@ -2,6 +2,16 @@ class Party < ApplicationRecord ##### ActiveRecord Associations + belongs_to :source_party, + class_name: 'Party', + foreign_key: :source_party_id, + optional: true + + has_many :derivative_parties, + class_name: 'Party', + foreign_key: :source_party_id, + inverse_of: :source_party + belongs_to :user, optional: true belongs_to :raid, optional: true belongs_to :job, optional: true @@ -29,21 +39,37 @@ class Party < ApplicationRecord has_many :characters, foreign_key: 'party_id', class_name: 'GridCharacter', - dependent: :destroy + dependent: :destroy, + inverse_of: :party has_many :weapons, foreign_key: 'party_id', class_name: 'GridWeapon', - dependent: :destroy + dependent: :destroy, + inverse_of: :party has_many :summons, foreign_key: 'party_id', class_name: 'GridSummon', - dependent: :destroy + dependent: :destroy, + inverse_of: :party has_many :favorites - before_save :set_shortcode + before_create :set_shortcode + + ##### Amoeba configuration + amoeba do + enable + + nullify :description + nullify :shortcode + + include_association :characters + include_association :weapons + include_association :summons + end + ##### ActiveRecord Validations validate :skills_are_unique From fa2962ae1cc8b396d65f01467ba74af68570db9d Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:48:36 -0800 Subject: [PATCH 09/13] Add remix method to parties controller --- app/controllers/api/v1/parties_controller.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index 5db36d6..ced5028 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -55,6 +55,19 @@ module Api end def remix + new_party = @party.amoeba_dup + new_party.attributes = { + user: current_user, + + source_party: @party + } + + if new_party.save + render json: PartyBlueprint.render(new_party, view: :full, root: :party, + meta: { remix: true }) + else + render_validation_error_response(new_party) + end end def index @@ -111,7 +124,7 @@ module Api def build_conditions(params) unless params['recency'].blank? start_time = (DateTime.current - params['recency'].to_i.seconds) - .to_datetime.beginning_of_day + .to_datetime.beginning_of_day end {}.tap do |hash| From b6e8dd93b1d6f5a6df62c6125e5bf8c61a4eb985 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 8 Jan 2023 21:49:25 -0800 Subject: [PATCH 10/13] Add party validation and inverse to GridObject associations --- app/models/grid_character.rb | 5 ++++- app/models/grid_summon.rb | 5 ++++- app/models/grid_weapon.rb | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index e60bcf9..b6bb12e 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true class GridCharacter < ApplicationRecord - belongs_to :party + belongs_to :party, + counter_cache: :weapons_count, + inverse_of: :characters + validates_presence_of :party validate :awakening_level, on: :update validate :transcendence, on: :update diff --git a/app/models/grid_summon.rb b/app/models/grid_summon.rb index 9857a9b..565a708 100644 --- a/app/models/grid_summon.rb +++ b/app/models/grid_summon.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true class GridSummon < ApplicationRecord - belongs_to :party + belongs_to :party, + counter_cache: :weapons_count, + inverse_of: :summons + validates_presence_of :party def summon Summon.find(summon_id) diff --git a/app/models/grid_weapon.rb b/app/models/grid_weapon.rb index 98c35cc..72d93cc 100644 --- a/app/models/grid_weapon.rb +++ b/app/models/grid_weapon.rb @@ -2,7 +2,9 @@ class GridWeapon < ApplicationRecord belongs_to :party, - counter_cache: :weapons_count + counter_cache: :weapons_count, + inverse_of: :weapons + validates_presence_of :party belongs_to :weapon_key1, class_name: 'WeaponKey', foreign_key: :weapon_key1_id, optional: true belongs_to :weapon_key2, class_name: 'WeaponKey', foreign_key: :weapon_key2_id, optional: true @@ -29,6 +31,8 @@ class GridWeapon < ApplicationRecord return unless weapon.limit party.weapons.find do |party_weapon| + return unless party_weapon.id + id_match = weapon.id == party_weapon.id series_match = weapon.series == party_weapon.weapon.series both_opus_or_draconic = weapon.opus_or_draconic? && party_weapon.weapon.opus_or_draconic? From 79b9b4e22563bf68393c19e47376b7cac14c28c4 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 9 Jan 2023 00:05:18 -0800 Subject: [PATCH 11/13] Exclude certain values from remixing --- app/models/grid_character.rb | 36 ++++++++++++++++++++++++------------ app/models/grid_weapon.rb | 8 ++++++++ app/models/party.rb | 2 -- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index b6bb12e..0e03291 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -12,34 +12,46 @@ class GridCharacter < ApplicationRecord validate :over_mastery_hp, on: :update validate :over_mastery_attack_matches_hp, on: :update + ##### Amoeba configuration + amoeba do + nullify :ring1 + nullify :ring2 + nullify :ring3 + nullify :ring4 + nullify :earring + nullify :perpetuity + end + def awakening_level - unless awakening.nil? - errors.add(:awakening, 'awakening level too low') if awakening["level"] < 1 - errors.add(:awakening, 'awakening level too high') if awakening["level"] > 9 - end + return if awakening.nil? + + 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 errors.add(:transcendence_step, 'character has no transcendence') if transcendence_step > 0 && !character.ulb errors.add(:transcendence_step, 'transcendence step too high') if transcendence_step > 5 && character.ulb errors.add(:transcendence_step, 'transcendence step too low') if transcendence_step < 0 && character.ulb - end def over_mastery_attack - errors.add(:ring1, 'invalid value') unless ring1["modifier"].nil? || atk_values.include?(ring1["strength"]) + errors.add(:ring1, 'invalid value') unless ring1['modifier'].nil? || atk_values.include?(ring1['strength']) end def over_mastery_hp - unless ring2["modifier"].nil? - errors.add(:ring2, 'invalid value') unless hp_values.include?(ring2["strength"]) - end + return if ring2['modifier'].nil? + + errors.add(:ring2, 'invalid value') unless hp_values.include?(ring2['strength']) end def over_mastery_attack_matches_hp - unless ring1[:modifier].nil? && ring2[:modifier].nil? - errors.add(:over_mastery, 'over mastery attack and hp values do not match') unless ring2[:strength] == (ring1[:strength] / 2) - end + return if ring1[:modifier].nil? && ring2[:modifier].nil? + + return if ring2[:strength] == (ring1[:strength] / 2) + + errors.add(:over_mastery, + 'over mastery attack and hp values do not match') end def character diff --git a/app/models/grid_weapon.rb b/app/models/grid_weapon.rb index 72d93cc..1048290 100644 --- a/app/models/grid_weapon.rb +++ b/app/models/grid_weapon.rb @@ -13,6 +13,14 @@ class GridWeapon < ApplicationRecord validate :compatible_with_position, on: :create validate :no_conflicts, on: :create + ##### Amoeba configuration + amoeba do + nullify :ax_modifier1 + nullify :ax_modifier2 + nullify :ax_strength1 + nullify :ax_strength2 + end + # Helper methods def blueprint GridWeaponBlueprint diff --git a/app/models/party.rb b/app/models/party.rb index 40330d8..87dd9d4 100644 --- a/app/models/party.rb +++ b/app/models/party.rb @@ -60,8 +60,6 @@ class Party < ApplicationRecord ##### Amoeba configuration amoeba do - enable - nullify :description nullify :shortcode From f73593d8e12c3554a01bd0c8647561a92dae5824 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 9 Jan 2023 00:29:01 -0800 Subject: [PATCH 12/13] Blank values using defaults instead of null --- app/models/grid_character.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index 0e03291..b3f7f38 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -14,12 +14,12 @@ class GridCharacter < ApplicationRecord ##### Amoeba configuration amoeba do - nullify :ring1 - nullify :ring2 - nullify :ring3 - nullify :ring4 - nullify :earring - nullify :perpetuity + set ring1: { modifier: nil, strength: nil } + set ring2: { modifier: nil, strength: nil } + set ring3: { modifier: nil, strength: nil } + set ring4: { modifier: nil, strength: nil } + set earring: { modifier: nil, strength: nil } + set perpetuity: false end def awakening_level From 18ca78a272e4be630b5829dc9351e3bdaf789800 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 9 Jan 2023 00:29:12 -0800 Subject: [PATCH 13/13] Implement localized remix names --- app/controllers/api/v1/parties_controller.rb | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index ced5028..81578b5 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -58,7 +58,7 @@ module Api new_party = @party.amoeba_dup new_party.attributes = { user: current_user, - + name: remixed_name(@party.name), source_party: @party } @@ -135,6 +135,24 @@ module Api end end + 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' + "Remix of #{blanked_name[:en]}" + when 'ja' + "#{blanked_name[:ja]}のリミックス" + end + else + "Remix of #{blanked_name[:en]}" + end + end + def set_from_slug @party = Party.where('shortcode = ?', params[:id]).first if @party