diff --git a/app/blueprints/api/v1/guidebook_blueprint.rb b/app/blueprints/api/v1/guidebook_blueprint.rb new file mode 100644 index 0000000..21536ac --- /dev/null +++ b/app/blueprints/api/v1/guidebook_blueprint.rb @@ -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 diff --git a/app/blueprints/api/v1/party_blueprint.rb b/app/blueprints/api/v1/party_blueprint.rb index 6b8e19f..fe6674d 100644 --- a/app/blueprints/api/v1/party_blueprint.rb +++ b/app/blueprints/api/v1/party_blueprint.rb @@ -40,6 +40,14 @@ module Api p.is_remix end + 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 + association :raid, blueprint: RaidBlueprint diff --git a/app/controllers/api/v1/guidebooks_controller.rb b/app/controllers/api/v1/guidebooks_controller.rb new file mode 100644 index 0000000..5d4cf8c --- /dev/null +++ b/app/controllers/api/v1/guidebooks_controller.rb @@ -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 diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index 5767706..8bbd66a 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -55,8 +55,8 @@ module Api # 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 @@ -263,7 +263,10 @@ module Api :clear_time, :button_count, :turn_count, - :chain_count + :chain_count, + :guidebook1_id, + :guidebook2_id, + :guidebook3_id ) end end diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index 336704f..0d94ae0 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -196,6 +196,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) diff --git a/app/models/guidebook.rb b/app/models/guidebook.rb new file mode 100644 index 0000000..581068a --- /dev/null +++ b/app/models/guidebook.rb @@ -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 :jp_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 diff --git a/app/models/party.rb b/app/models/party.rb index 8345471..5729698 100644 --- a/app/models/party.rb +++ b/app/models/party.rb @@ -41,6 +41,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', @@ -80,6 +95,7 @@ class Party < ApplicationRecord ##### ActiveRecord Validations validate :skills_are_unique + validate :guidebooks_are_unique attr_accessor :favorited @@ -130,4 +146,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 diff --git a/config/routes.rb b/config/routes.rb index fe827c9..9218e0f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -34,6 +34,7 @@ Rails.application.routes.draw do 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' @@ -41,6 +42,8 @@ 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 'weapon_keys', to: 'weapon_keys#all' diff --git a/db/migrate/20230418052314_add_guidebooks.rb b/db/migrate/20230418052314_add_guidebooks.rb new file mode 100644 index 0000000..c74e306 --- /dev/null +++ b/db/migrate/20230418052314_add_guidebooks.rb @@ -0,0 +1,12 @@ +class AddGuidebooks < ActiveRecord::Migration[7.0] + def change + create_table :guidebooks, id: :uuid, default: -> { "gen_random_uuid()" } do |t| + t.string :granblue_id, null: false, unique: true + t.string :name_en, null: false, unique: true + t.string :name_jp, null: false, unique: true + t.string :description_en, null: false + t.string :description_jp, null: false + t.timestamps + end + end +end diff --git a/db/migrate/20230418052325_add_guidebooks_to_party.rb b/db/migrate/20230418052325_add_guidebooks_to_party.rb new file mode 100644 index 0000000..9c05639 --- /dev/null +++ b/db/migrate/20230418052325_add_guidebooks_to_party.rb @@ -0,0 +1,5 @@ +class AddGuidebooksToParty < ActiveRecord::Migration[7.0] + def change + add_column :parties, :guidebooks, :uuid, array: true, default: [], null: false + end +end diff --git a/db/migrate/20230418061932_update_guidebooks_structure.rb b/db/migrate/20230418061932_update_guidebooks_structure.rb new file mode 100644 index 0000000..c7005df --- /dev/null +++ b/db/migrate/20230418061932_update_guidebooks_structure.rb @@ -0,0 +1,6 @@ +class UpdateGuidebooksStructure < ActiveRecord::Migration[7.0] + def change + remove_column :guidebooks, :updated_at + change_column_default :guidebooks, :created_at, -> { 'CURRENT_TIMESTAMP' } + end +end diff --git a/db/migrate/20230418071647_rename_guidebooks_to_guidebook_i_ds.rb b/db/migrate/20230418071647_rename_guidebooks_to_guidebook_i_ds.rb new file mode 100644 index 0000000..7b80062 --- /dev/null +++ b/db/migrate/20230418071647_rename_guidebooks_to_guidebook_i_ds.rb @@ -0,0 +1,5 @@ +class RenameGuidebooksToGuidebookIDs < ActiveRecord::Migration[7.0] + def change + rename_column :parties, :guidebooks, :guidebook_ids + end +end diff --git a/db/migrate/20230419033648_split_guidebooks_on_party.rb b/db/migrate/20230419033648_split_guidebooks_on_party.rb new file mode 100644 index 0000000..08dc2d2 --- /dev/null +++ b/db/migrate/20230419033648_split_guidebooks_on_party.rb @@ -0,0 +1,8 @@ +class SplitGuidebooksOnParty < ActiveRecord::Migration[7.0] + def change + remove_column :parties, :guidebook_ids + add_reference :parties, :guidebook0, type: :uuid, foreign_key: { to_table: :guidebooks } + add_reference :parties, :guidebook1, type: :uuid, foreign_key: { to_table: :guidebooks } + add_reference :parties, :guidebook2, type: :uuid, foreign_key: { to_table: :guidebooks } + end +end diff --git a/db/migrate/20230419102354_rename_guidebook_columns.rb b/db/migrate/20230419102354_rename_guidebook_columns.rb new file mode 100644 index 0000000..f7116f6 --- /dev/null +++ b/db/migrate/20230419102354_rename_guidebook_columns.rb @@ -0,0 +1,5 @@ +class RenameGuidebookColumns < ActiveRecord::Migration[7.0] + def change + rename_column :parties, :guidebook0_id, :guidebook3_id + end +end diff --git a/db/migrate/20230423070004_add_gacha_table.rb b/db/migrate/20230423070004_add_gacha_table.rb new file mode 100644 index 0000000..264051a --- /dev/null +++ b/db/migrate/20230423070004_add_gacha_table.rb @@ -0,0 +1,13 @@ +class AddGachaTable < ActiveRecord::Migration[7.0] + create_table :gacha, id: :uuid, default: -> { "gen_random_uuid()" } do |t| + t.references :drawable, polymorphic: true + t.boolean :premium + t.boolean :classic + t.boolean :flash + t.boolean :legend + t.boolean :valentines + t.boolean :summer + t.boolean :halloween + t.boolean :holiday + end +end diff --git a/db/migrate/20230423071446_add_recruits_to_weapon.rb b/db/migrate/20230423071446_add_recruits_to_weapon.rb new file mode 100644 index 0000000..21dbf1e --- /dev/null +++ b/db/migrate/20230423071446_add_recruits_to_weapon.rb @@ -0,0 +1,5 @@ +class AddRecruitsToWeapon < ActiveRecord::Migration[7.0] + def change + add_reference :weapons, :recruits, null: true, to_table: 'character_id', type: :uuid + end +end diff --git a/db/migrate/20230423125524_change_gacha_drawable_id_to_uuid.rb b/db/migrate/20230423125524_change_gacha_drawable_id_to_uuid.rb new file mode 100644 index 0000000..e274ffe --- /dev/null +++ b/db/migrate/20230423125524_change_gacha_drawable_id_to_uuid.rb @@ -0,0 +1,7 @@ +class ChangeGachaDrawableIdToUuid < ActiveRecord::Migration[7.0] + def change + remove_column :gacha, :drawable_id, :bigint + remove_column :gacha, :drawable_type, :string + add_reference :gacha, :drawable, polymorphic: true, type: :uuid + end +end diff --git a/db/migrate/20230423132430_make_gacha_drawable_id_unique.rb b/db/migrate/20230423132430_make_gacha_drawable_id_unique.rb new file mode 100644 index 0000000..3181999 --- /dev/null +++ b/db/migrate/20230423132430_make_gacha_drawable_id_unique.rb @@ -0,0 +1,5 @@ +class MakeGachaDrawableIdUnique < ActiveRecord::Migration[7.0] + def change + add_index :gacha, :drawable_id, unique: true + end +end diff --git a/db/migrate/20230502012823_add_gacha_rateups_table.rb b/db/migrate/20230502012823_add_gacha_rateups_table.rb new file mode 100644 index 0000000..da7c72f --- /dev/null +++ b/db/migrate/20230502012823_add_gacha_rateups_table.rb @@ -0,0 +1,8 @@ +class AddGachaRateupsTable < ActiveRecord::Migration[7.0] + create_table :gacha_rateups, id: :uuid, default: -> { "gen_random_uuid()" } do |t| + t.references :gacha, type: :uuid + t.string :user_id + t.numeric :rate + t.datetime :created_at, null: false, default: -> { 'CURRENT_TIMESTAMP' } + end +end diff --git a/db/migrate/20230503221903_add_sparks_table.rb b/db/migrate/20230503221903_add_sparks_table.rb new file mode 100644 index 0000000..fca83e0 --- /dev/null +++ b/db/migrate/20230503221903_add_sparks_table.rb @@ -0,0 +1,11 @@ +class AddSparksTable < ActiveRecord::Migration[7.0] + create_table :sparks, id: :uuid, default: -> { "gen_random_uuid()" } do |t| + t.string :user_id, null: false + t.string :guild_ids, array: true, null: false + t.integer :crystals, default: 0 + t.integer :tickets, default: 0 + t.integer :ten_tickets, default: 0 + t.references :target, polymorphic: true + t.datetime :updated_at, null: false, default: -> { 'CURRENT_TIMESTAMP' } + end +end diff --git a/db/migrate/20230503224345_add_target_memo_to_sparks.rb b/db/migrate/20230503224345_add_target_memo_to_sparks.rb new file mode 100644 index 0000000..c31caea --- /dev/null +++ b/db/migrate/20230503224345_add_target_memo_to_sparks.rb @@ -0,0 +1,5 @@ +class AddTargetMemoToSparks < ActiveRecord::Migration[7.0] + def change + add_column :sparks, :target_memo, :string + end +end diff --git a/db/migrate/20230503224353_make_user_id_unique_in_sparks.rb b/db/migrate/20230503224353_make_user_id_unique_in_sparks.rb new file mode 100644 index 0000000..16ffff6 --- /dev/null +++ b/db/migrate/20230503224353_make_user_id_unique_in_sparks.rb @@ -0,0 +1,5 @@ +class MakeUserIdUniqueInSparks < ActiveRecord::Migration[7.0] + def change + add_index :sparks, :user_id, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index b0dc946..ad74e64 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do +ActiveRecord::Schema[7.0].define(version: 2023_05_03_224353) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_trgm" @@ -124,6 +124,29 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do t.index ["user_id"], name: "index_favorites_on_user_id" end + create_table "gacha", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.boolean "premium" + t.boolean "classic" + t.boolean "flash" + t.boolean "legend" + t.boolean "valentines" + t.boolean "summer" + t.boolean "halloween" + t.boolean "holiday" + t.string "drawable_type" + t.uuid "drawable_id" + t.index ["drawable_id"], name: "index_gacha_on_drawable_id", unique: true + t.index ["drawable_type", "drawable_id"], name: "index_gacha_on_drawable" + end + + create_table "gacha_rateups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "gacha_id" + t.string "user_id" + t.decimal "rate" + t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }, null: false + t.index ["gacha_id"], name: "index_gacha_rateups_on_gacha_id" + end + create_table "grid_characters", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "party_id" t.uuid "character_id" @@ -187,6 +210,15 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do t.index ["weapon_key3_id"], name: "index_grid_weapons_on_weapon_key3_id" end + create_table "guidebooks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "granblue_id", null: false + t.string "name_en", null: false + t.string "name_jp", null: false + t.string "description_en", null: false + t.string "description_jp", null: false + t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }, null: false + end + create_table "job_accessories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "job_id" t.string "name_en", null: false @@ -297,7 +329,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do t.string "edit_key" t.uuid "local_id" t.integer "ultimate_mastery" + t.uuid "guidebook3_id" + t.uuid "guidebook1_id" + t.uuid "guidebook2_id" t.index ["accessory_id"], name: "index_parties_on_accessory_id" + t.index ["guidebook1_id"], name: "index_parties_on_guidebook1_id" + t.index ["guidebook2_id"], name: "index_parties_on_guidebook2_id" + t.index ["guidebook3_id"], name: "index_parties_on_guidebook3_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" @@ -316,6 +354,20 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do t.string "slug" end + create_table "sparks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "user_id", null: false + t.string "guild_ids", null: false, array: true + t.integer "crystals", default: 0 + t.integer "tickets", default: 0 + t.integer "ten_tickets", default: 0 + t.string "target_type" + t.bigint "target_id" + t.datetime "updated_at", default: -> { "CURRENT_TIMESTAMP" }, null: false + t.string "target_memo" + t.index ["target_type", "target_id"], name: "index_sparks_on_target" + t.index ["user_id"], name: "index_sparks_on_user_id", unique: true + end + create_table "summons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name_en" t.string "name_jp" @@ -398,7 +450,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do t.integer "awakening_types", default: [], array: true t.string "nicknames_en", default: [], null: false, array: true t.string "nicknames_jp", default: [], null: false, array: true + t.uuid "recruits_id" t.index ["name_en"], name: "index_weapons_on_name_en", opclass: :gin_trgm_ops, using: :gin + t.index ["recruits_id"], name: "index_weapons_on_recruits_id" end add_foreign_key "favorites", "parties" @@ -413,6 +467,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_21_115930) do 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", "guidebooks", column: "guidebook1_id" + add_foreign_key "parties", "guidebooks", column: "guidebook2_id" + add_foreign_key "parties", "guidebooks", column: "guidebook3_id" add_foreign_key "parties", "job_accessories", column: "accessory_id" add_foreign_key "parties", "job_skills", column: "skill0_id" add_foreign_key "parties", "job_skills", column: "skill1_id"