From 6cf9c8d2ae41130b9cf5479ca5caac587b9cb2e4 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 6 Jan 2023 01:29:09 -0800 Subject: [PATCH 01/10] Create 20230106023753_change_awakening_type_default_value.rb --- .../20230106023753_change_awakening_type_default_value.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20230106023753_change_awakening_type_default_value.rb diff --git a/db/migrate/20230106023753_change_awakening_type_default_value.rb b/db/migrate/20230106023753_change_awakening_type_default_value.rb new file mode 100644 index 0000000..89d0f01 --- /dev/null +++ b/db/migrate/20230106023753_change_awakening_type_default_value.rb @@ -0,0 +1,5 @@ +class ChangeAwakeningTypeDefaultValue < ActiveRecord::Migration[7.0] + def change + change_column :grid_characters, :awakening_type, :integer, null: false, default: 1 + end +end From 7404bcbac9691f0ac0272815ed25483ecc88990a Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 05:33:16 -0800 Subject: [PATCH 02/10] Change mastery columns to use jsonb 5 columns better than 10 --- ...7121520_change_mastery_columns_to_jsonb.rb | 22 +++++++++++++++++++ db/schema.rb | 19 ++++++---------- 2 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20230107121520_change_mastery_columns_to_jsonb.rb diff --git a/db/migrate/20230107121520_change_mastery_columns_to_jsonb.rb b/db/migrate/20230107121520_change_mastery_columns_to_jsonb.rb new file mode 100644 index 0000000..b8319cc --- /dev/null +++ b/db/migrate/20230107121520_change_mastery_columns_to_jsonb.rb @@ -0,0 +1,22 @@ +class ChangeMasteryColumnsToJsonb < ActiveRecord::Migration[7.0] + def change + # Remove old columns + remove_column :grid_characters, :ring_modifier1, :integer + remove_column :grid_characters, :ring_modifier2, :integer + remove_column :grid_characters, :ring_modifier3, :integer + remove_column :grid_characters, :ring_modifier4, :integer + remove_column :grid_characters, :ring_strength1, :integer + remove_column :grid_characters, :ring_strength2, :integer + remove_column :grid_characters, :ring_strength3, :integer + remove_column :grid_characters, :ring_strength4, :integer + remove_column :grid_characters, :earring_modifier, :integer + remove_column :grid_characters, :earring_strength, :integer + + # Add new columns + add_column :grid_characters, :ring1, :jsonb, default: { modifier: nil, strength: nil } + add_column :grid_characters, :ring2, :jsonb, default: { modifier: nil, strength: nil } + add_column :grid_characters, :ring3, :jsonb, default: { modifier: nil, strength: nil } + add_column :grid_characters, :ring4, :jsonb, default: { modifier: nil, strength: nil } + add_column :grid_characters, :earring, :jsonb, default: { modifier: nil, strength: nil } + end +end diff --git a/db/schema.rb b/db/schema.rb index 0b5c6cb..e6a1429 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_01_03_180458) do +ActiveRecord::Schema[7.0].define(version: 2023_01_07_121520) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_trgm" @@ -67,19 +67,14 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_03_180458) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "perpetuity", default: false, null: false - t.integer "awakening_type", default: 0, null: false + t.integer "awakening_type", default: 1, null: false t.integer "awakening_level", default: 1, null: false t.integer "transcendence_step", default: 0, null: false - t.integer "ring_modifier1" - t.float "ring_strength1" - t.integer "ring_modifier2" - t.float "ring_strength2" - t.integer "ring_modifier3" - t.float "ring_strength3" - t.integer "ring_modifier4" - t.float "ring_strength4" - t.integer "earring_modifier" - t.float "earring_strength" + t.jsonb "ring1", default: {"modifier"=>nil, "strength"=>nil} + t.jsonb "ring2", default: {"modifier"=>nil, "strength"=>nil} + t.jsonb "ring3", default: {"modifier"=>nil, "strength"=>nil} + t.jsonb "ring4", default: {"modifier"=>nil, "strength"=>nil} + t.jsonb "earring", default: {"modifier"=>nil, "strength"=>nil} t.index ["character_id"], name: "index_grid_characters_on_character_id" t.index ["party_id"], name: "index_grid_characters_on_party_id" end From a2fff663d605a3802d16c3ab5c38831ec5e6f879 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 07:49:28 -0800 Subject: [PATCH 03/10] More database updates for mastery cols * Awakening should be jsonb * All mastery columns are not nullable --- ...107150547_change_awakening_columns_to_jsonb.rb | 10 ++++++++++ ...107153724_make_mastery_columns_not_nullable.rb | 10 ++++++++++ db/schema.rb | 15 +++++++-------- 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20230107150547_change_awakening_columns_to_jsonb.rb create mode 100644 db/migrate/20230107153724_make_mastery_columns_not_nullable.rb diff --git a/db/migrate/20230107150547_change_awakening_columns_to_jsonb.rb b/db/migrate/20230107150547_change_awakening_columns_to_jsonb.rb new file mode 100644 index 0000000..3a48821 --- /dev/null +++ b/db/migrate/20230107150547_change_awakening_columns_to_jsonb.rb @@ -0,0 +1,10 @@ +class ChangeAwakeningColumnsToJsonb < ActiveRecord::Migration[7.0] + def change + # Remove old columns + remove_column :grid_characters, :awakening_type, :integer + remove_column :grid_characters, :awakening_level, :integer + + # Add new column + add_column :grid_characters, :awakening, :jsonb, default: { type: 1, level: 1 } + end +end diff --git a/db/migrate/20230107153724_make_mastery_columns_not_nullable.rb b/db/migrate/20230107153724_make_mastery_columns_not_nullable.rb new file mode 100644 index 0000000..976ca5a --- /dev/null +++ b/db/migrate/20230107153724_make_mastery_columns_not_nullable.rb @@ -0,0 +1,10 @@ +class MakeMasteryColumnsNotNullable < ActiveRecord::Migration[7.0] + def change + change_column :grid_characters, :ring1, :jsonb, null: false + change_column :grid_characters, :ring2, :jsonb, null: false + change_column :grid_characters, :ring3, :jsonb, null: false + change_column :grid_characters, :ring4, :jsonb, null: false + change_column :grid_characters, :earring, :jsonb, null: false + change_column :grid_characters, :awakening, :jsonb, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index e6a1429..4cea1cb 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_01_07_121520) do +ActiveRecord::Schema[7.0].define(version: 2023_01_07_153724) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_trgm" @@ -67,14 +67,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_07_121520) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "perpetuity", default: false, null: false - t.integer "awakening_type", default: 1, null: false - t.integer "awakening_level", default: 1, null: false t.integer "transcendence_step", default: 0, null: false - t.jsonb "ring1", default: {"modifier"=>nil, "strength"=>nil} - t.jsonb "ring2", default: {"modifier"=>nil, "strength"=>nil} - t.jsonb "ring3", default: {"modifier"=>nil, "strength"=>nil} - t.jsonb "ring4", default: {"modifier"=>nil, "strength"=>nil} - t.jsonb "earring", default: {"modifier"=>nil, "strength"=>nil} + 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 From beb9f5aa0cda365e7c4169310c3d17dd3c7831d2 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 07:49:39 -0800 Subject: [PATCH 04/10] Add GridCharacters#update route --- config/routes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/routes.rb b/config/routes.rb index 91094d7..8256840 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Rails.application.routes.draw do resources :parties, only: %i[index create update destroy] resources :users, only: %i[create update show] resources :grid_weapons, only: [:update] + resources :grid_characters, only: [:update] resources :favorites, only: [:create] get 'users/info/:id', to: 'users#info' From 5351123aa2901f912ed594c5ffb848a2081d5a37 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 07:51:04 -0800 Subject: [PATCH 05/10] Add basic validation for various mastery bonuses * Ensure transcendence is possible on that character * Ensure transcendence_step is in bounds * Ensure Over Mastery Attack is a valid value * Ensure Over Mastery HP is a valid value * Ensure Over Mastery Attack is 2x Over Mastery HP * Ensure Awakening level is in bounds --- app/blueprints/api/v1/error_blueprint.rb | 4 +++ app/models/grid_character.rb | 46 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/app/blueprints/api/v1/error_blueprint.rb b/app/blueprints/api/v1/error_blueprint.rb index 78a431a..29796c0 100644 --- a/app/blueprints/api/v1/error_blueprint.rb +++ b/app/blueprints/api/v1/error_blueprint.rb @@ -14,6 +14,10 @@ module Api field :errors, if: ->(_field_name, _error, options) { options.key?(:exception) } do |_, options| options[:exception] end + + field :errors, if: ->(_field_name, object, options) { options.key?(:errors) } do |_, options| + options[:errors] + end end end end diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index 2e3e16b..e60bcf9 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -3,6 +3,42 @@ class GridCharacter < ApplicationRecord belongs_to :party + validate :awakening_level, on: :update + validate :transcendence, on: :update + validate :over_mastery_attack, on: :update + validate :over_mastery_hp, on: :update + validate :over_mastery_attack_matches_hp, on: :update + + 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 + 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"]) + end + + def over_mastery_hp + unless ring2["modifier"].nil? + errors.add(:ring2, 'invalid value') unless hp_values.include?(ring2["strength"]) + end + 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 + end + def character Character.find(character_id) end @@ -10,4 +46,14 @@ class GridCharacter < ApplicationRecord def blueprint GridCharacterBlueprint end + + private + + def atk_values + [300, 600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000] + end + + def hp_values + [150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500] + end end From 3617088418f6e64e40558d46b3954cf47c605ec3 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 07:51:40 -0800 Subject: [PATCH 06/10] Add update method for GridCharacter and other utils * Add check_authorization for before update and eventually destroy runs * Update permitted parameters --- .../api/v1/grid_characters_controller.rb | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/grid_characters_controller.rb b/app/controllers/api/v1/grid_characters_controller.rb index 2f68524..347ef93 100644 --- a/app/controllers/api/v1/grid_characters_controller.rb +++ b/app/controllers/api/v1/grid_characters_controller.rb @@ -6,6 +6,8 @@ module Api attr_reader :party, :incoming_character, :current_characters before_action :find_party, only: :create + before_action :set, only: [:update, :destroy] + before_action :check_authorization, only: [:update, :destroy] before_action :find_incoming_character, only: :create before_action :find_current_characters, only: :create @@ -37,6 +39,22 @@ module Api end end + def update + mastery = {} + [:ring1, :ring2, :ring3, :ring4, :earring, :awakening].each do |key| + value = character_params.to_h[key] + mastery[key] = value unless value.nil? + end + + @character.attributes = character_params.merge(mastery) + + if @character.save + return render json: GridCharacterBlueprint.render(@character, view: :full) if @character.save + else + render_validation_error_response(@character) + end + end + def resolve incoming = Character.find(resolve_params[:incoming]) conflicting = resolve_params[:conflicting].map { |id| GridCharacter.find(id) } @@ -103,6 +121,10 @@ module Api end.flatten end + def set + @character = GridCharacter.find(character_params[:id]) + end + def find_incoming_character @incoming_character = Character.find(character_params[:character_id]) end @@ -112,10 +134,21 @@ module Api render_unauthorized_response if current_user && (party.user != current_user) end + def check_authorization + render_unauthorized_response if @character.party.user != current_user + end + # Specify whitelisted properties that can be modified. def character_params - params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level, :conflicting, - :incoming) + params.require(:character).permit(:id, :party_id, :character_id, :position, + :uncap_level, :transcendence_step, :perpetuity, + :ring1 => [:modifier, :strength], :ring2 => [:modifier, :strength], + :ring3 => [:modifier, :strength], :ring4 => [:modifier, :strength], + :earring => [:modifier, :strength], :awakening => [:type, :level]) + end + + def resolve_params + params.require(:resolve).permit(:position, :incoming, conflicting: []) end def render_conflict_view(conflict_characters, incoming_character, incoming_position) @@ -129,10 +162,6 @@ module Api def render_grid_character_view(grid_character) GridCharacterBlueprint.render(grid_character, view: :nested) end - - def resolve_params - params.require(:resolve).permit(:position, :incoming, conflicting: []) - end end end end From 8f9bd0077e727b02682354e7b22d925add0b7d92 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 7 Jan 2023 07:51:54 -0800 Subject: [PATCH 07/10] Add new fields to output of GridCharacter --- .../api/v1/grid_character_blueprint.rb | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/app/blueprints/api/v1/grid_character_blueprint.rb b/app/blueprints/api/v1/grid_character_blueprint.rb index c753940..4ef5e97 100644 --- a/app/blueprints/api/v1/grid_character_blueprint.rb +++ b/app/blueprints/api/v1/grid_character_blueprint.rb @@ -11,13 +11,40 @@ module Api view :nested do fields :position, :uncap_level, :perpetuity - field :awakening do |c| + field :transcendence_step, if: ->(_fn, obj, _opt) { + obj.character.ulb + } do |c| + c.transcendence_step + end + + field :awakening, if: ->(_fn, obj, _opt) { + !obj[:awakening].nil? + } do |c| { - type: c.awakening_type, - level: c.awakening_level + type: c.awakening[:type], + level: c.awakening[:level] } end + field :over_mastery, if: ->(_fn, obj, _opt) { + !obj.ring1['modifier'].nil? && !obj.ring2['modifier'].nil? + } do |c| + rings = [] + + rings.push(c.ring1) if !c.ring1['modifier'].nil? + rings.push(c.ring2) if !c.ring2['modifier'].nil? + rings.push(c.ring3) if !c.ring3['modifier'].nil? + rings.push(c.ring4) if !c.ring4['modifier'].nil? + + rings + end + + field :aetherial_mastery, if: ->(_fn, obj, _opt) { + !obj.earring['modifier'].nil? + } do |c| + c.earring + end + association :character, name: :object, blueprint: CharacterBlueprint end From 73022778f67b138e7b35377531d5a284a9832034 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 9 Jan 2023 01:51:38 -0800 Subject: [PATCH 08/10] Add server-side validation for OM and AM rings Note: Over mastery is not validating properly yet --- app/models/grid_character.rb | 168 +++++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 15 deletions(-) diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index e60bcf9..ac8faea 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -5,40 +5,60 @@ class GridCharacter < ApplicationRecord validate :awakening_level, on: :update validate :transcendence, on: :update - validate :over_mastery_attack, on: :update - validate :over_mastery_hp, on: :update + validate :validate_over_mastery_values, on: :update + validate :validate_aetherial_mastery_value, on: :update validate :over_mastery_attack_matches_hp, on: :update 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, 'character has no transcendence') if transcendence_step.positive? && !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 - + errors.add(:transcendence_step, 'transcendence step too low') if transcendence_step.negative? && 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) + 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 validate_over_mastery_values + [ring1, ring2, ring3, ring4].each_with_index do |ring, index| + next if ring['modifier'].nil? + + modifier = over_mastery_modifiers[ring['modifier']] + check_value({ "ring#{index}": { ring[modifier] => ring['strength'] } }, + 'over_mastery') end end + def validate_aetherial_mastery_value + return if earring['modifier'].nil? + + modifier = aetherial_mastery_modifiers[earring['modifier']].to_sym + check_value({ "earring": { modifier => earring['strength'] } }, + 'aetherial_mastery') + end + def character Character.find(character_id) end @@ -49,6 +69,124 @@ class GridCharacter < ApplicationRecord private + def check_value(property, type) + # Input format + # { ring1: { atk: 300 } } + + key = property.keys.first + modifier = property[key].keys.first + + return if modifier.nil? + + case type + when 'over_mastery' + errors.add(key, 'invalid value') unless over_mastery_values.include?(key['strength']) + when 'aetherial_mastery' + errors.add(key, 'value too low') if aetherial_mastery_values[modifier][:min] > self[key]['strength'] + errors.add(key, 'value too high') if aetherial_mastery_values[modifier][:max] < self[key]['strength'] + end + end + + def over_mastery_modifiers + { + 1 => 'atk', + 2 => 'hp', + 3 => 'debuff_success', + 4 => 'skill_cap', + 5 => 'ca_dmg', + 6 => 'ca_cap', + 7 => 'stamina', + 8 => 'enmity', + 9 => 'crit', + 10 => 'da', + 11 => 'ta', + 12 => 'def', + 13 => 'heal', + 14 => 'debuff_resist', + 15 => 'dodge' + } + end + + def over_mastery_values + { + atk: [300, 600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000], + hp: [150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500], + debuff_success: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + skill_cap: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ca_dmg: [10, 12, 14, 16, 18, 20, 22, 24, 27, 30], + ca_cap: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + crit: [10, 12, 14, 16, 18, 20, 22, 24, 27, 30], + enmity: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + stamina: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + def: [6, 7, 8, 9, 10, 12, 14, 16, 18, 20], + heal: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30], + debuff_resist: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + dodge: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + da: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ta: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + } + end + + def aetherial_mastery_modifiers + { + 1 => 'da', + 2 => 'ta', + 3 => 'ele_atk', + 4 => 'ele_resist', + 5 => 'stamina', + 6 => 'enmity', + 7 => 'supplemental', + 8 => 'crit', + 9 => 'counter_dodge', + 10 => 'counter_dmg' + } + end + + def aetherial_mastery_values + { + da: { + min: 10, + max: 17 + }, + ta: { + min: 5, + max: 12 + }, + ele_atk: { + min: 15, + max: 22 + }, + ele_resist: { + min: 5, + max: 12 + }, + stamina: { + min: 5, + max: 12 + }, + enmity: { + min: 5, + max: 12 + }, + supplemental: { + min: 5, + max: 12 + }, + crit: { + min: 18, + max: 35 + }, + counter_dodge: { + min: 5, + max: 12 + }, + counter_dmg: { + min: 10, + max: 17 + } + } + end + def atk_values [300, 600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000] end From 633db43e949078d22a16490463b4e4765282e964 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Fri, 20 Jan 2023 21:39:20 -0800 Subject: [PATCH 09/10] Implement removing characters and weapons --- .../api/v1/grid_character_blueprint.rb | 27 +++++++++---------- .../api/v1/grid_weapon_blueprint.rb | 4 +++ .../api/v1/grid_characters_controller.rb | 21 +++++++++------ .../api/v1/grid_weapons_controller.rb | 17 +++++++----- app/models/grid_character.rb | 2 ++ config/routes.rb | 4 +-- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/app/blueprints/api/v1/grid_character_blueprint.rb b/app/blueprints/api/v1/grid_character_blueprint.rb index 4ef5e97..4ecf072 100644 --- a/app/blueprints/api/v1/grid_character_blueprint.rb +++ b/app/blueprints/api/v1/grid_character_blueprint.rb @@ -11,35 +11,30 @@ module Api view :nested do fields :position, :uncap_level, :perpetuity - field :transcendence_step, if: ->(_fn, obj, _opt) { + field :transcendence_step, if: lambda { |_fn, obj, _opt| obj.character.ulb } do |c| c.transcendence_step end - field :awakening, if: ->(_fn, obj, _opt) { - !obj[:awakening].nil? - } do |c| - { - type: c.awakening[:type], - level: c.awakening[:level] - } + field :awakening do |c| + c.awakening end - field :over_mastery, if: ->(_fn, obj, _opt) { + field :over_mastery, if: lambda { |_fn, obj, _opt| !obj.ring1['modifier'].nil? && !obj.ring2['modifier'].nil? } do |c| rings = [] - rings.push(c.ring1) if !c.ring1['modifier'].nil? - rings.push(c.ring2) if !c.ring2['modifier'].nil? - rings.push(c.ring3) if !c.ring3['modifier'].nil? - rings.push(c.ring4) if !c.ring4['modifier'].nil? + 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: ->(_fn, obj, _opt) { + field :aetherial_mastery, if: lambda { |_fn, obj, _opt| !obj.earring['modifier'].nil? } do |c| c.earring @@ -52,6 +47,10 @@ module Api include_view :nested association :party, blueprint: PartyBlueprint, view: :minimal end + + view :destroyed do + fields :position, :created_at, :updated_at + end end end end diff --git a/app/blueprints/api/v1/grid_weapon_blueprint.rb b/app/blueprints/api/v1/grid_weapon_blueprint.rb index a2ff815..3e409e8 100644 --- a/app/blueprints/api/v1/grid_weapon_blueprint.rb +++ b/app/blueprints/api/v1/grid_weapon_blueprint.rb @@ -43,6 +43,10 @@ module Api include_view :nested association :party, blueprint: PartyBlueprint, view: :minimal end + + view :destroyed do + fields :mainhand, :position, :created_at, :updated_at + end end end end diff --git a/app/controllers/api/v1/grid_characters_controller.rb b/app/controllers/api/v1/grid_characters_controller.rb index 347ef93..23d9381 100644 --- a/app/controllers/api/v1/grid_characters_controller.rb +++ b/app/controllers/api/v1/grid_characters_controller.rb @@ -6,8 +6,8 @@ module Api attr_reader :party, :incoming_character, :current_characters before_action :find_party, only: :create - before_action :set, only: [:update, :destroy] - before_action :check_authorization, only: [:update, :destroy] + before_action :set, only: %i[update destroy] + before_action :check_authorization, only: %i[update destroy] before_action :find_incoming_character, only: :create before_action :find_current_characters, only: :create @@ -41,7 +41,7 @@ module Api def update mastery = {} - [:ring1, :ring2, :ring3, :ring4, :earring, :awakening].each do |key| + %i[ring1 ring2 ring3 ring4 earring awakening].each do |key| value = character_params.to_h[key] mastery[key] = value unless value.nil? end @@ -49,8 +49,10 @@ module Api @character.attributes = character_params.merge(mastery) if @character.save + ap 'Saved character' return render json: GridCharacterBlueprint.render(@character, view: :full) if @character.save else + ap 'Could not save' render_validation_error_response(@character) end end @@ -94,7 +96,10 @@ module Api end # TODO: Implement removing characters - def destroy; end + def destroy + render_unauthorized_response if @character.party.user != current_user + return render json: GridCharacterBlueprint.render(@character, view: :destroyed) if @character.destroy + end private @@ -122,7 +127,7 @@ module Api end def set - @character = GridCharacter.find(character_params[:id]) + @character = GridCharacter.find(params[:id]) end def find_incoming_character @@ -142,9 +147,9 @@ module Api def character_params params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level, :transcendence_step, :perpetuity, - :ring1 => [:modifier, :strength], :ring2 => [:modifier, :strength], - :ring3 => [:modifier, :strength], :ring4 => [:modifier, :strength], - :earring => [:modifier, :strength], :awakening => [:type, :level]) + ring1: %i[modifier strength], ring2: %i[modifier strength], + ring3: %i[modifier strength], ring4: %i[modifier strength], + earring: %i[modifier strength], awakening: %i[type level]) end def resolve_params diff --git a/app/controllers/api/v1/grid_weapons_controller.rb b/app/controllers/api/v1/grid_weapons_controller.rb index 94c9563..7282161 100644 --- a/app/controllers/api/v1/grid_weapons_controller.rb +++ b/app/controllers/api/v1/grid_weapons_controller.rb @@ -3,7 +3,7 @@ module Api module V1 class GridWeaponsController < Api::V1::ApiController - before_action :set, except: %w[create update_uncap_level destroy] + before_action :set, except: %w[create update_uncap_level] attr_reader :party, :incoming_weapon @@ -56,7 +56,10 @@ module Api end # TODO: Implement removing characters - def destroy; end + def destroy + render_unauthorized_response if @weapon.party.user != current_user + return render json: GridCharacterBlueprint.render(@weapon, view: :destroyed) if @weapon.destroy + end def update_uncap_level weapon = GridWeapon.find(weapon_params[:id]) @@ -115,15 +118,15 @@ module Api # Render the conflict view as a string def render_conflict_view(conflict_weapon, incoming_weapon, incoming_position) ConflictBlueprint.render(nil, view: :weapons, - conflict_weapon: conflict_weapon, - incoming_weapon: incoming_weapon, - incoming_position: incoming_position) + conflict_weapon: conflict_weapon, + incoming_weapon: incoming_weapon, + incoming_position: incoming_position) end def render_grid_weapon_view(grid_weapon, conflict_position) GridWeaponBlueprint.render(grid_weapon, view: :full, - root: :grid_weapon, - meta: { replaced: conflict_position }) + root: :grid_weapon, + meta: { replaced: conflict_position }) end def save_weapon(weapon) diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index ac8faea..db4a3b3 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -54,6 +54,8 @@ class GridCharacter < ApplicationRecord def validate_aetherial_mastery_value return if earring['modifier'].nil? + return unless earring['modifier'].positive? + modifier = aetherial_mastery_modifiers[earring['modifier']].to_sym check_value({ "earring": { modifier => earring['strength'] } }, 'aetherial_mastery') diff --git a/config/routes.rb b/config/routes.rb index 8256840..38775d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,8 +8,8 @@ Rails.application.routes.draw do namespace :v1 do resources :parties, only: %i[index create update destroy] resources :users, only: %i[create update show] - resources :grid_weapons, only: [:update] - resources :grid_characters, only: [:update] + resources :grid_weapons, only: %i[update destroy] + resources :grid_characters, only: %i[update destroy] resources :favorites, only: [:create] get 'users/info/:id', to: 'users#info' From bd15d91cdd17ec9ad7435fcb37c0011e12584c0d Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sun, 22 Jan 2023 21:24:00 -0800 Subject: [PATCH 10/10] Fix grid character creation Grid characters were only replacing the character when replacing an existing character, so the mods were persisted. This creates a new GridCharacter every time a replacement happens and destroys the old one. --- .../api/v1/grid_characters_controller.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/grid_characters_controller.rb b/app/controllers/api/v1/grid_characters_controller.rb index 23d9381..74f521e 100644 --- a/app/controllers/api/v1/grid_characters_controller.rb +++ b/app/controllers/api/v1/grid_characters_controller.rb @@ -21,17 +21,16 @@ module Api conflict_view = render_conflict_view(conflict_characters, incoming_character, character_params[:position]) render json: conflict_view else - # Replace the grid character in the position if it is already filled + # Destroy 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)) + character.destroy end + # Then, create a new grid character + character = GridCharacter.create!(character_params.merge(party_id: party.id, + character_id: incoming_character.id)) + if character.save! grid_character_view = render_grid_character_view(character) render json: grid_character_view, status: :created