From a76bda993fe45c8cd8e6b919c85ae4bd37f7361d Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Thu, 17 Nov 2022 02:26:15 -0800 Subject: [PATCH 1/4] Add character_id field to character table This is used for deduping characters so users can't add two of the same character to a grid. --- db/migrate/20221117070255_add_character_id_to_characters.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20221117070255_add_character_id_to_characters.rb diff --git a/db/migrate/20221117070255_add_character_id_to_characters.rb b/db/migrate/20221117070255_add_character_id_to_characters.rb new file mode 100644 index 0000000..3d1ce90 --- /dev/null +++ b/db/migrate/20221117070255_add_character_id_to_characters.rb @@ -0,0 +1,5 @@ +class AddCharacterIdToCharacters < ActiveRecord::Migration[6.1] + def change + add_column :characters, :character_id, :integer, array: true, null: false, default: [] + end +end diff --git a/db/schema.rb b/db/schema.rb index 7980348..9d4fe9d 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.define(version: 2022_04_10_190152) do +ActiveRecord::Schema.define(version: 2022_11_17_070255) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" @@ -44,6 +44,7 @@ ActiveRecord::Schema.define(version: 2022_04_10_190152) do 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 From 33cef2050c5144953a16e2f78a9c07a1e0dbcd3e Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 19 Nov 2022 06:02:17 -0800 Subject: [PATCH 2/4] Added route for resolving character conflicts --- config/routes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/routes.rb b/config/routes.rb index 8532969..cf1c984 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,7 @@ Rails.application.routes.draw do get 'weapon_keys', to: 'weapon_keys#all' post 'characters', to: 'grid_characters#create' + post 'characters/resolve', to: 'grid_characters#resolve' post 'characters/update_uncap', to: 'grid_characters#update_uncap_level' delete 'characters', to: 'grid_characters#destroy' From c45a54e22256e919aed81ae4056cb4a360d0ee76 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 19 Nov 2022 06:02:33 -0800 Subject: [PATCH 3/4] Added character_id to character template --- app/views/api/v1/characters/base.json.rabl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/api/v1/characters/base.json.rabl b/app/views/api/v1/characters/base.json.rabl index 77c4f09..47976a3 100644 --- a/app/views/api/v1/characters/base.json.rabl +++ b/app/views/api/v1/characters/base.json.rabl @@ -2,6 +2,7 @@ object :character attributes :id, :granblue_id, + :character_id, :rarity, :element, :gender, @@ -64,4 +65,4 @@ node :ougi_ratio do |w| :ougi_ratio => w.ougi_ratio, :ougi_ratio_flb => w.ougi_ratio_flb } -end \ No newline at end of file +end From 559507977b4790b337465e1f377698dd2227a934 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 19 Nov 2022 06:03:39 -0800 Subject: [PATCH 4/4] Added logic for conflict resolution * Conflict is detected when attempting to save a new GridCharacter * New `resolve` method executes the replacement * Template to render a decision on the frontend --- .../api/v1/grid_characters_controller.rb | 76 ++++++++++++++++--- .../api/v1/grid_characters/conflict.json.rabl | 14 ++++ 2 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 app/views/api/v1/grid_characters/conflict.json.rabl diff --git a/app/controllers/api/v1/grid_characters_controller.rb b/app/controllers/api/v1/grid_characters_controller.rb index 6b6aa71..9d6ece3 100644 --- a/app/controllers/api/v1/grid_characters_controller.rb +++ b/app/controllers/api/v1/grid_characters_controller.rb @@ -1,7 +1,7 @@ class Api::V1::GridCharactersController < Api::V1::ApiController def create party = Party.find(character_params[:party_id]) - canonical_character = Character.find(character_params[:character_id]) + incoming_character = Character.find(character_params[:character_id]) if current_user if party.user != current_user @@ -9,13 +9,67 @@ class Api::V1::GridCharactersController < Api::V1::ApiController end end - if GridCharacter.where(party_id: party.id, position: character_params[:position]).exists? - @character = GridCharacter.where(party_id: party.id, position: character_params[:position]).limit(1)[0] - @character.character_id = canonical_character.id - else - @character = GridCharacter.create!(character_params.merge(party_id: party.id, character_id: canonical_character.id)) - end + current_characters = party.characters.map { |c| + Character.find(c.character.id).character_id + }.flatten + # Check all character ids on incoming character against current characters + conflict_ids = (current_characters & incoming_character.character_id) + + if conflict_ids.length > 0 + # Find conflicting character ids in party characters + conflict_characters = party.characters.filter { |c| + c if (conflict_ids & c.character.character_id).length > 0 + }.flatten + + # Render a template with the conflicting and incoming characters, + # as well as the selected position, so the user can be presented with + # a decision. + + # Up to 3 characters can be removed at the same time + @conflict_characters = conflict_characters + @incoming_character = incoming_character + @incoming_position = character_params[:position] + + render :conflict, status: :ok + else + # Replace the grid character in the position if it is already filled + if GridCharacter.where(party_id: party.id, position: character_params[:position]).exists? + @character = GridCharacter.where(party_id: party.id, position: character_params[:position]).limit(1)[0] + @character.character_id = incoming_character.id + + # Otherwise, create a new grid character + else + @character = GridCharacter.create!(character_params.merge(party_id: party.id, character_id: incoming_character.id)) + end + + render :show, status: :created if @character.save! + end + end + + def resolve + incoming = Character.find(resolve_params[:incoming]) + conflicting = resolve_params[:conflicting].map { |id| GridCharacter.find(id) } + party = conflicting.first.party + + # Destroy each conflicting character + conflicting.each { |character| GridCharacter.destroy(character.id) } + + # Destroy the character at the desired position if it exists + existing_character = GridCharacter.where(party: party.id, position: resolve_params[:position]).first + GridCharacter.destroy(existing_character.id) unless !existing_character + + if (incoming.special) + uncap_level = 3 + uncap_level = 5 if incoming.ulb + uncap_level = 4 if incoming.flb + else + uncap_level = 4 + uncap_level = 6 if incoming.ulb + uncap_level = 5 if incoming.flb + end + + @character = GridCharacter.create!(party_id: party.id, character_id: incoming.id, position: resolve_params[:position], uncap_level: uncap_level) render :show, status: :created if @character.save! end @@ -39,6 +93,10 @@ class Api::V1::GridCharactersController < Api::V1::ApiController # Specify whitelisted properties that can be modified. def character_params - params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level) + params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level, :conflicting, :incoming) end -end \ No newline at end of file + + def resolve_params + params.require(:resolve).permit(:position, :incoming, :conflicting => []) + end +end diff --git a/app/views/api/v1/grid_characters/conflict.json.rabl b/app/views/api/v1/grid_characters/conflict.json.rabl new file mode 100644 index 0000000..e67e0fc --- /dev/null +++ b/app/views/api/v1/grid_characters/conflict.json.rabl @@ -0,0 +1,14 @@ +object false + +node :conflicts do + partial('grid_characters/base', :object => @conflict_characters) +end + +node :incoming do + partial('characters/base', :object => @incoming_character) +end + +node :position do + @incoming_position +end + \ No newline at end of file