hensei-api/app/controllers/api/v1/import_controller.rb
Justin Edmund 3cdd925162
Fix filters and add processors (#181)
* Update test csvs

* Fix count filters and refactor apply_filters

* Update party_querying_concern.rb

* +tests/-debug logs

* Make party association optional in Job

* Updates for weapon series

- Change to new series numbers
- Add static method for querying whether the weapon's element is changeable
- Add a new method to return a text slug for the weapon's series

* Add and update test data

- Updates canonical.rb for loading multiple types of data with multiple types of associations
- Adds test data for Guidebooks, Job Accessories, Job Skills, and Jobs
- Updates test data for Weapons and Summons

* Migrations

- Adds series of migrations for changing the weapon's series to the values used by Cygames
- Shuffled around some foreign keys

* Implement BaseProcessor

Processors are in charge of processing deck data straight from Granblue.

* Implement CharacterProcessor

Process character data from deck

* Implement WeaponProcessor

Process weapon data from deck

* Implement JobProcessor

Process job, job skill, and job accessory data from deck

* Implement SummonProcessor

Process summon data from deck

* Update SummonProcessor to work like the others

* ImportController should use processors

* Process element for changeable weapons
2025-02-17 23:51:50 -08:00

111 lines
3.7 KiB
Ruby

# frozen_string_literal: true
module Api
module V1
##
# ImportController is responsible for importing game data (e.g. deck data)
# and creating a new Party along with associated records (job, characters, weapons, summons, etc.).
#
# The controller expects a JSON payload whose top-level key is "import". If not wrapped,
# the controller will wrap the raw data automatically.
#
# @example Valid payload structure
# {
# "import": {
# "deck": { "name": "My Party", ... },
# "pc": { "job": { "master": { "name": "Warrior" } }, ... }
# }
# }
class ImportController < Api::V1::ApiController
ELEMENT_MAPPING = {
0 => nil,
1 => 4,
2 => 2,
3 => 3,
4 => 1,
5 => 6,
6 => 5
}.freeze
##
# Processes an import request.
#
# It reads and parses the raw JSON, wraps the data under the "import" key if necessary,
# transforms the deck data using BaseDeckTransformer, validates that the transformed data
# contains required fields, and then creates a new Party record (and its associated objects)
# inside a transaction.
#
# @return [void] Renders JSON response with a party shortcode or an error message.
def create
Rails.logger.info '[IMPORT] Checking input...'
body = parse_request_body
return unless body
raw_params = body['import']
unless raw_params.is_a?(Hash)
Rails.logger.error "[IMPORT] 'import' key is missing or not a hash."
return render json: { error: 'Invalid JSON data' }, status: :unprocessable_content
end
unless raw_params['deck'].is_a?(Hash) &&
raw_params['deck'].key?('pc') &&
raw_params['deck'].key?('npc')
Rails.logger.error "[IMPORT] Deck data incomplete or missing."
return render json: { error: 'Invalid deck data' }, status: :unprocessable_content
end
Rails.logger.info '[IMPORT] Starting import...'
return if performed? # Rendered an error response already
party = Party.create(user: current_user)
deck_data = raw_params['import']
process_data(party, deck_data)
render json: { shortcode: party.shortcode }, status: :created
rescue StandardError => e
render json: { error: e.message }, status: :unprocessable_content
end
private
##
# Reads and parses the raw JSON request body.
#
# @return [Hash] Parsed JSON data.
# @raise [JSON::ParserError] If the JSON is invalid.
def parse_request_body
raw_body = request.raw_post
JSON.parse(raw_body)
rescue JSON::ParserError => e
Rails.logger.error "[IMPORT] Invalid JSON: #{e.message}"
render json: { error: 'Invalid JSON data' }, status: :bad_request and return
end
##
# Ensures that the provided data is wrapped under an "import" key.
#
# @param data [Hash] The parsed JSON data.
# @return [Hash] Data wrapped under the "import" key.
def wrap_import_data(data)
data.key?('import') ? data : { 'import' => data }
end
##
# Processes the deck data using processors.
#
# @param party [Party] The party to insert data into
# @param data [Hash] The wrapped data.
# @return [Hash] The transformed deck data.
def process_data(party, data)
Rails.logger.info '[IMPORT] Transforming deck data'
Processors::JobProcessor.new(party, data).process
Processors::CharacterProcessor.new(party, data).process
Processors::SummonProcessor.new(party, data).process
Processors::WeaponProcessor.new(party, data).process
end
end
end
end