diff --git a/Gemfile b/Gemfile index e247f01..586f285 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,10 @@ source 'https://rubygems.org' ruby '3.0.0' -gem 'rails' -gem 'pg' gem 'bootsnap' +gem 'pg' gem 'rack-cors' +gem 'rails' # A Ruby Web Server Built For Concurrency gem 'puma' @@ -16,8 +16,8 @@ gem 'bcrypt' # Doorkeeper is an OAuth 2 provider for Rails and Grape. gem 'doorkeeper' -# Templating system with JSON, XML and Plist support. -gem 'rabl' +# Simple, Fast, and Declarative Serialization Library for Ruby +gem 'blueprinter' # Optimized JSON. gem 'oj' @@ -35,7 +35,7 @@ gem 'gemoji-parser' gem 'awesome_nested_set' # An email validator for Rails -gem "email_validator" +gem 'email_validator' # pg_search builds ActiveRecord named scopes that take advantage of PostgreSQL’s full text search gem 'pg_search' @@ -44,31 +44,31 @@ gem 'pg_search' gem 'will_paginate', '~> 3.3' group :doc do - gem 'sdoc' - gem 'apipie-rails' + gem 'apipie-rails' + gem 'sdoc' end group :development, :test do - gem 'awesome_print' - gem 'dotenv-rails' - gem 'factory_bot_rails' - gem 'faker' - gem 'rspec-rails' - gem 'rspec_junit_formatter' + gem 'awesome_print' + gem 'dotenv-rails' + gem 'factory_bot_rails' + gem 'faker' + gem 'rspec_junit_formatter' + gem 'rspec-rails' end group :development do - gem 'listen' - gem 'rubocop' - gem 'solargraph' - gem 'spring-commands-rspec' - gem 'spring' + gem 'listen' + gem 'rubocop' + gem 'solargraph' + gem 'spring' + gem 'spring-commands-rspec' end group :test do - gem 'api_matchers' - gem 'byebug' - gem 'database_cleaner' - gem 'shoulda-matchers' - gem 'simplecov', :require => false + gem 'api_matchers' + gem 'byebug' + gem 'database_cleaner' + gem 'shoulda-matchers' + gem 'simplecov', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index c7f2096..eb88c9c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,6 +73,7 @@ GEM backport (1.2.0) bcrypt (3.1.16) benchmark (0.2.0) + blueprinter (0.25.3) bootsnap (1.9.1) msgpack (~> 1.0) builder (3.2.4) @@ -147,8 +148,6 @@ GEM activesupport (>= 5.2) puma (5.5.2) nio4r (~> 2.0) - rabl (0.14.5) - activesupport (>= 2.3.14) racc (1.6.0) rack (2.2.3) rack-cors (1.1.1) @@ -286,6 +285,7 @@ DEPENDENCIES awesome_nested_set awesome_print bcrypt + blueprinter bootsnap byebug database_cleaner @@ -301,7 +301,6 @@ DEPENDENCIES pg pg_search puma - rabl rack-cors rails responders diff --git a/app/blueprints/api/v1/api_blueprint.rb b/app/blueprints/api/v1/api_blueprint.rb new file mode 100644 index 0000000..edae6bb --- /dev/null +++ b/app/blueprints/api/v1/api_blueprint.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Api + module V1 + class ApiBlueprint < Blueprinter::Base + identifier :id + + cattr_accessor :current_user + cattr_writer :current_user + end + end +end diff --git a/app/blueprints/api/v1/character_blueprint.rb b/app/blueprints/api/v1/character_blueprint.rb new file mode 100644 index 0000000..d47bde7 --- /dev/null +++ b/app/blueprints/api/v1/character_blueprint.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Api + module V1 + class CharacterBlueprint < ApiBlueprint + field :name do |w| + { + en: w.name_en, + ja: w.name_jp + } + end + + fields :granblue_id, :character_id, :rarity, + :element, :gender, :special + + field :uncap do |w| + { + flb: w.flb, + ulb: w.ulb + } + end + + field :hp do |w| + { + min_hp: w.min_hp, + max_hp: w.max_hp, + max_hp_flb: w.max_hp_flb + } + end + + field :atk do |w| + { + min_atk: w.min_atk, + max_atk: w.max_atk, + max_atk_flb: w.max_atk_flb + } + end + + field :race do |w| + [ + w.race1, + w.race2 + ] + end + + field :proficiency do |w| + [ + w.proficiency1, + w.proficiency2 + ] + end + + field :data do |w| + { + base_da: w.base_da, + base_ta: w.base_ta + } + end + + field :ougi_ratio do |w| + { + ougi_ratio: w.ougi_ratio, + ougi_ratio_flb: w.ougi_ratio_flb + } + end + end + end +end diff --git a/app/blueprints/api/v1/conflict_blueprint.rb b/app/blueprints/api/v1/conflict_blueprint.rb new file mode 100644 index 0000000..eccfab1 --- /dev/null +++ b/app/blueprints/api/v1/conflict_blueprint.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Api + module V1 + class ConflictBlueprint < Blueprinter::Base + field :position, if: ->(_fn, _obj, options) { options.key?(:incoming_position) } do |_, options| + options[:incoming_position] + end + + view :characters do + field :conflicts, if: ->(_fn, _obj, options) { options.key?(:conflict_characters) } do |_, options| + GridCharacterBlueprint.render_as_hash(options[:conflict_characters], view: :nested) + end + + field :incoming, if: ->(_fn, _obj, options) { options.key?(:incoming_character) } do |_, options| + CharacterBlueprint.render_as_hash(options[:incoming_character]) + end + end + + view :weapons do + field :conflicts, if: ->(_fn, _obj, options) { options.key?(:conflict_weapons) } do |_, options| + GridWeaponBlueprint.render_as_hash(options[:conflict_weapons], view: :nested) + end + + field :incoming, if: ->(_fn, _obj, options) { options.key?(:incoming_weapon) } do |_, options| + WeaponBlueprint.render_as_hash(options[:incoming_weapon]) + end + end + end + end +end diff --git a/app/blueprints/api/v1/empty_blueprint.rb b/app/blueprints/api/v1/empty_blueprint.rb new file mode 100644 index 0000000..ad8b861 --- /dev/null +++ b/app/blueprints/api/v1/empty_blueprint.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Api + module V1 + class EmptyBlueprint < Blueprinter::Base + field :available, if: ->(_field_name, _empty, options) { options.key?(:availability) } do |_, options| + if options.key?(:email) + User.where('email = ?', options[:email]).count.zero? + elsif options.key?(:username) + User.where('username = ?', options[:username]).count.zero? + end + end + end + end +end diff --git a/app/blueprints/api/v1/error_blueprint.rb b/app/blueprints/api/v1/error_blueprint.rb new file mode 100644 index 0000000..78a431a --- /dev/null +++ b/app/blueprints/api/v1/error_blueprint.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Api + module V1 + class ErrorBlueprint < Blueprinter::Base + field :error, if: ->(_field_name, _error, options) { options.key?(:error) } do |_, options| + options[:error] + end + + field :errors, if: ->(_field_name, _error, options) { options.key?(:errors) } do |_, options| + options[:errors] + end + + field :errors, if: ->(_field_name, _error, options) { options.key?(:exception) } do |_, options| + options[:exception] + end + end + end +end diff --git a/app/blueprints/api/v1/favorite_blueprint.rb b/app/blueprints/api/v1/favorite_blueprint.rb new file mode 100644 index 0000000..60aa642 --- /dev/null +++ b/app/blueprints/api/v1/favorite_blueprint.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Api + module V1 + class FavoriteBlueprint < ApiBlueprint + association :user, + name: :user, + blueprint: UserBlueprint, + view: :minimal + + association :party, + name: :party, + blueprint: PartyBlueprint, + view: :preview + + fields :created_at, :updated_at + + view :destroyed do + field :destroyed do + true + end + end + end + end +end diff --git a/app/blueprints/api/v1/grid_character_blueprint.rb b/app/blueprints/api/v1/grid_character_blueprint.rb new file mode 100644 index 0000000..c3aff00 --- /dev/null +++ b/app/blueprints/api/v1/grid_character_blueprint.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Api + module V1 + class GridCharacterBlueprint < ApiBlueprint + view :uncap do + association :party, blueprint: PartyBlueprint, view: :minimal + fields :position, :uncap_level + end + + view :nested do + fields :position, :uncap_level, :perpetuity + association :character, name: :object, blueprint: CharacterBlueprint + end + + view :full do + include_view :nested + association :party, blueprint: PartyBlueprint, view: :minimal + end + end + end +end diff --git a/app/blueprints/api/v1/grid_summon_blueprint.rb b/app/blueprints/api/v1/grid_summon_blueprint.rb new file mode 100644 index 0000000..af2cec6 --- /dev/null +++ b/app/blueprints/api/v1/grid_summon_blueprint.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Api + module V1 + class GridSummonBlueprint < ApiBlueprint + view :uncap do + association :party, blueprint: PartyBlueprint, view: :minimal + fields :position, :uncap_level + end + + view :nested do + fields :main, :friend, :position, :uncap_level + association :summon, name: :object, blueprint: SummonBlueprint + end + + view :full do + include_view :nested + association :party, blueprint: PartyBlueprint, view: :minimal + end + end + end +end diff --git a/app/blueprints/api/v1/grid_weapon_blueprint.rb b/app/blueprints/api/v1/grid_weapon_blueprint.rb new file mode 100644 index 0000000..0c28a26 --- /dev/null +++ b/app/blueprints/api/v1/grid_weapon_blueprint.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Api + module V1 + class GridWeaponBlueprint < ApiBlueprint + view :uncap do + association :party, blueprint: PartyBlueprint, view: :minimal + fields :position, :uncap_level + end + + view :nested do + fields :mainhand, :position, :uncap_level, :element + association :weapon, name: :object, blueprint: WeaponBlueprint + + association :weapon_keys, + blueprint: WeaponKeyBlueprint, + if: lambda { |_field_name, w, _options| + [2, 3, 17, 22].include?(w.weapon.series) + } + + field :ax, if: ->(_field_name, w, _options) { w.weapon.ax.positive? } do |w| + [ + { + modifier: w.ax_modifier1, + strength: w.ax_strength1 + }, + { + modifier: w.ax_modifier2, + strength: w.ax_strength2 + } + ] + end + end + + view :full do + include_view :nested + association :party, blueprint: PartyBlueprint, view: :minimal + end + end + end +end diff --git a/app/blueprints/api/v1/job_blueprint.rb b/app/blueprints/api/v1/job_blueprint.rb new file mode 100644 index 0000000..319a62b --- /dev/null +++ b/app/blueprints/api/v1/job_blueprint.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Api + module V1 + class JobBlueprint < ApiBlueprint + field :name do |job| + { + en: job.name_en, + ja: job.name_jp + } + end + + field :proficiency do |job| + [ + job.proficiency1, + job.proficiency2 + ] + end + + fields :row, :ml, :order + end + end +end diff --git a/app/blueprints/api/v1/job_skill_blueprint.rb b/app/blueprints/api/v1/job_skill_blueprint.rb new file mode 100644 index 0000000..b6b79b1 --- /dev/null +++ b/app/blueprints/api/v1/job_skill_blueprint.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Api + module V1 + class JobSkillBlueprint < ApiBlueprint + field :name do |skill| + { + en: skill.name_en, + ja: skill.name_jp + } + end + + association :job, + name: :job, + blueprint: JobBlueprint + + fields :slug, :color, :main, :base, :sub, :emp, :order + end + end +end diff --git a/app/blueprints/api/v1/party_blueprint.rb b/app/blueprints/api/v1/party_blueprint.rb new file mode 100644 index 0000000..db539fd --- /dev/null +++ b/app/blueprints/api/v1/party_blueprint.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module Api + module V1 + class PartyBlueprint < ApiBlueprint + view :weapons do + association :weapons, + blueprint: GridWeaponBlueprint, + view: :nested + end + + view :summons do + association :summons, + blueprint: GridSummonBlueprint, + view: :nested + end + + view :characters do + association :characters, + blueprint: GridCharacterBlueprint, + view: :nested + end + + view :job_skills do + field :job_skills do |job| + { + '0' => !job.skill0.nil? ? JobSkillBlueprint.render_as_hash(job.skill0) : nil, + '1' => !job.skill1.nil? ? JobSkillBlueprint.render_as_hash(job.skill1) : nil, + '2' => !job.skill2.nil? ? JobSkillBlueprint.render_as_hash(job.skill2) : nil, + '3' => !job.skill3.nil? ? JobSkillBlueprint.render_as_hash(job.skill3) : nil + } + end + end + + view :minimal do + fields :name, :element, :shortcode, :favorited, :extra, :created_at, :updated_at + + association :raid, + blueprint: RaidBlueprint + + association :job, + blueprint: JobBlueprint + + association :user, + blueprint: UserBlueprint, + view: :minimal + end + + view :jobs do + association :job, + blueprint: JobBlueprint + include_view :job_skills + end + + view :preview do + include_view :minimal + include_view :weapons + end + + view :full do + include_view :preview + include_view :summons + include_view :characters + include_view :job_skills + + fields :description, :extra + end + + view :collection do + include_view :preview + end + + view :destroyed do + fields :name, :description, :created_at, :updated_at + end + end + end +end diff --git a/app/blueprints/api/v1/raid_blueprint.rb b/app/blueprints/api/v1/raid_blueprint.rb new file mode 100644 index 0000000..295c09a --- /dev/null +++ b/app/blueprints/api/v1/raid_blueprint.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Api + module V1 + class RaidBlueprint < ApiBlueprint + field :name do |raid| + { + en: raid.name_en, + ja: raid.name_jp + } + end + + fields :slug, :level, :group, :element + end + end +end diff --git a/app/blueprints/api/v1/summon_blueprint.rb b/app/blueprints/api/v1/summon_blueprint.rb new file mode 100644 index 0000000..3db846d --- /dev/null +++ b/app/blueprints/api/v1/summon_blueprint.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Api + module V1 + class SummonBlueprint < ApiBlueprint + field :name do |w| + { + en: w.name_en, + ja: w.name_jp + } + end + + fields :granblue_id, :element, :rarity, :max_level + + field :uncap do |w| + { + flb: w.flb, + ulb: w.ulb + } + end + + field :hp do |w| + { + min_hp: w.min_hp, + max_hp: w.max_hp, + max_hp_flb: w.max_hp_flb, + max_hp_ulb: w.max_hp_ulb + } + end + + field :atk do |w| + { + min_atk: w.min_atk, + max_atk: w.max_atk, + max_atk_flb: w.max_atk_flb, + max_atk_ulb: w.max_atk_ulb + } + end + end + end +end diff --git a/app/blueprints/api/v1/user_blueprint.rb b/app/blueprints/api/v1/user_blueprint.rb new file mode 100644 index 0000000..dace3a7 --- /dev/null +++ b/app/blueprints/api/v1/user_blueprint.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Api + module V1 + class UserBlueprint < ApiBlueprint + view :minimal do + fields :username, :language, :private, :gender + field :avatar do |user| + { + picture: user.picture, + element: user.element + } + end + end + + view :profile do + include_view :minimal + + field :parties, if: ->(_fn, _obj, options) { options[:parties].length.positive? } do |_, options| + PartyBlueprint.render_as_hash(options[:parties], view: :preview) + end + end + + view :token do + fields :username, :token + end + + view :settings do + fields :email + end + end + end +end diff --git a/app/blueprints/api/v1/weapon_blueprint.rb b/app/blueprints/api/v1/weapon_blueprint.rb new file mode 100644 index 0000000..5d715da --- /dev/null +++ b/app/blueprints/api/v1/weapon_blueprint.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Api + module V1 + class WeaponBlueprint < ApiBlueprint + field :name do |w| + { + en: w.name_en, + ja: w.name_jp + } + end + + fields :granblue_id, :element, :proficiency, + :max_level, :max_skill_level, :limit, :rarity, + :series, :ax + + field :uncap do |w| + { + flb: w.flb, + ulb: w.ulb + } + end + + field :hp do |w| + { + min_hp: w.min_hp, + max_hp: w.max_hp, + max_hp_flb: w.max_hp_flb, + max_hp_ulb: w.max_hp_ulb + } + end + + field :atk do |w| + { + min_atk: w.min_atk, + max_atk: w.max_atk, + max_atk_flb: w.max_atk_flb, + max_atk_ulb: w.max_atk_ulb + } + end + end + end +end diff --git a/app/blueprints/api/v1/weapon_key_blueprint.rb b/app/blueprints/api/v1/weapon_key_blueprint.rb new file mode 100644 index 0000000..64ed12f --- /dev/null +++ b/app/blueprints/api/v1/weapon_key_blueprint.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Api + module V1 + class WeaponKeyBlueprint < ApiBlueprint + field :name do |key| + { + en: key.name_en, + ja: key.name_jp + } + end + + fields :series, :slot, :group, :order + end + end +end diff --git a/app/controllers/api/v1/api_controller.rb b/app/controllers/api/v1/api_controller.rb index 79e13a9..2aceddc 100644 --- a/app/controllers/api/v1/api_controller.rb +++ b/app/controllers/api/v1/api_controller.rb @@ -1,80 +1,100 @@ -module Api::V1 - class ApiController < ActionController::API - ##### Doorkeeper - include Doorkeeper::Rails::Helpers +# frozen_string_literal: true - ##### Errors - rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotDestroyed, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response - rescue_from ActiveRecord::RecordNotSaved, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotUnique, with: :render_unprocessable_entity_response - rescue_from Api::V1::SameFavoriteUserError, with: :render_unprocessable_entity_response - rescue_from Api::V1::FavoriteAlreadyExistsError, with: :render_unprocessable_entity_response - rescue_from Api::V1::NoJobProvidedError, with: :render_unprocessable_entity_response - rescue_from Api::V1::TooManySkillsOfTypeError, with: :render_unprocessable_entity_response - rescue_from Api::V1::UnauthorizedError, with: :render_unauthorized_response - rescue_from ActionController::ParameterMissing, with: :render_unprocessable_entity_response +module Api + module V1 + class ApiController < ActionController::API + ##### Doorkeeper + include Doorkeeper::Rails::Helpers - rescue_from GranblueError do |e| - render_error(e) - end + ##### Errors + rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotDestroyed, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response_without_object + rescue_from ActiveRecord::RecordNotSaved, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotUnique, with: :render_unprocessable_entity_response + rescue_from Api::V1::SameFavoriteUserError, with: :render_unprocessable_entity_response + rescue_from Api::V1::FavoriteAlreadyExistsError, with: :render_unprocessable_entity_response + rescue_from Api::V1::NoJobProvidedError, with: :render_unprocessable_entity_response + rescue_from Api::V1::TooManySkillsOfTypeError, with: :render_unprocessable_entity_response + rescue_from Api::V1::UnauthorizedError, with: :render_unauthorized_response + rescue_from ActionController::ParameterMissing, with: :render_unprocessable_entity_response - ##### Hooks - before_action :current_user - before_action :set_default_content_type - - ##### Responders - respond_to :json - - ##### Methods - # Assign the current user if the Doorkeeper token isn't nil, then - # update the current user's last seen datetime and last IP address - # before returning - def current_user - @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token - - return @current_user - end - - # Set the response content-type - def set_content_type(content_type) - response.headers["Content-Type"] = content_type - end - - # Set the default response content-type to application/javascript - # with a UTF-8 charset - def set_default_content_type - set_content_type("application/javascript; charset=utf-8") - end - - ### Error response methods - def render_error(error) - if error - render action: 'errors', json: error.to_hash, status: error.http_status - else - render action: 'errors' + rescue_from GranblueError do |e| + render_error(e) end - end - def render_unprocessable_entity_response(exception) - @exception = exception - render action: 'errors', status: :unprocessable_entity - end + ##### Hooks + before_action :current_user + before_action :default_content_type - def render_not_found_response - response = { errors: [{ message: "Record could not be found.", code: "not_found" }] } - render 'not_found', status: :not_found - end + ##### Responders + respond_to :json - def render_unauthorized_response - render action: 'errors', status: :unauthorized - end + ##### Methods + # Assign the current user if the Doorkeeper token isn't nil, then + # update the current user's last seen datetime and last IP address + # before returning + def current_user + @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token - private + @current_user + end - def restrict_access - raise UnauthorizedError unless current_user + # Set the response content-type + def content_type(content_type) + response.headers['Content-Type'] = content_type + end + + # Set the default response content-type to application/javascript + # with a UTF-8 charset + def default_content_type + content_type('application/javascript; charset=utf-8') + end + + ### Error response methods + def render_error(error) + if error + render action: 'errors', json: error.to_hash, status: error.http_status + else + render action: 'errors' + end + end + + def render_unprocessable_entity_response(exception) + render json: ErrorBlueprint.render_as_json(nil, exception: exception), + status: :unprocessable_entity + end + + def render_validation_error_response(object) + render json: ErrorBlueprint.render_as_json(nil, errors: object.errors), + status: :unprocessable_entity + end + + def render_not_found_response_without_object + render json: ErrorBlueprint.render(nil, + error: { + message: 'Object could not be found', + code: 'not_found' + }), status: :not_found + end + + def render_not_found_response(object) + render json: ErrorBlueprint.render(nil, error: { + message: "#{object.capitalize} could not be found", + code: 'not_found' + }), status: :not_found + end + + def render_unauthorized_response + render json: ErrorBlueprint.render_as_json(nil), + status: :unauthorized + end + + private + + def restrict_access + raise UnauthorizedError unless current_user + end end end end diff --git a/app/controllers/api/v1/favorites_controller.rb b/app/controllers/api/v1/favorites_controller.rb index 26da814..4f5279b 100644 --- a/app/controllers/api/v1/favorites_controller.rb +++ b/app/controllers/api/v1/favorites_controller.rb @@ -1,41 +1,51 @@ -class Api::V1::FavoritesController < Api::V1::ApiController - before_action :set_party, only: ['create'] +# frozen_string_literal: true - def create +module Api + module V1 + class FavoritesController < Api::V1::ApiController + before_action :set_party, only: ['create'] + + def create party_id = favorite_params[:party_id] party = Party.find(party_id) - if !current_user - raise Api::V1::UnauthorizedError - elsif party.user && current_user.id == party.user.id - raise Api::V1::SameFavoriteUserError - elsif Favorite.where(user_id: current_user.id, party_id: party_id).length > 0 - raise Api::V1::FavoriteAlreadyExistsError - else - object = { - user_id: current_user.id, - party_id: favorite_params[:party_id] - } + raise Api::V1::UnauthorizedError unless current_user + raise Api::V1::SameFavoriteUserError if party.user && current_user.id == party.user.id + raise Api::V1::FavoriteAlreadyExistsError if Favorite.where(user_id: current_user.id, + party_id: party_id).length.positive? - @favorite = Favorite.new(object) - render :show, status: :created if @favorite.save! + @favorite = Favorite.new({ + user_id: current_user.id, + party_id: party_id + }) + + if @favorite.save! + return render json: FavoriteBlueprint.render(@favorite, root: :favorite), + status: :created end - end - def destroy + render_validation_error_response(@favorite) + end + + def destroy raise Api::V1::UnauthorizedError unless current_user @favorite = Favorite.where(user_id: current_user.id, party_id: favorite_params[:party_id]).first - render :destroyed, status: :ok if @favorite && Favorite.destroy(@favorite.id) - end + render_not_found_response('favorite') unless @favorite - private + render_error("Couldn't delete favorite") unless Favorite.destroy(@favorite.id) + render json: FavoriteBlueprint.render(@favorite, root: :favorite, view: :destroyed) + end - def set_party - @party = Party.where("id = ?", params[:party_id]).first - end + private - def favorite_params + def set_party + @party = Party.where('id = ?', params[:party_id]).first + end + + def favorite_params params.require(:favorite).permit(:party_id) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/api/v1/grid_characters_controller.rb b/app/controllers/api/v1/grid_characters_controller.rb index 9d6ece3..31674cd 100644 --- a/app/controllers/api/v1/grid_characters_controller.rb +++ b/app/controllers/api/v1/grid_characters_controller.rb @@ -1,53 +1,53 @@ -class Api::V1::GridCharactersController < Api::V1::ApiController - def create +# frozen_string_literal: true + +module Api + module V1 + class GridCharactersController < Api::V1::ApiController + def create party = Party.find(character_params[:party_id]) incoming_character = Character.find(character_params[:character_id]) - if current_user - if party.user != current_user - render_unauthorized_response - end - end + render_unauthorized_response if current_user && (party.user != current_user) - current_characters = party.characters.map { |c| - Character.find(c.character.id).character_id - }.flatten + current_characters = party.characters.map do |c| + Character.find(c.character.id).character_id + end.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. + if conflict_ids.length.positive? + # Find conflicting character ids in party characters + conflict_characters = party.characters.filter do |c| + c if (conflict_ids & c.character.character_id).length.positive? + end.flatten - # 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 a template with the conflicting and incoming characters, + # as well as the selected position, so the user can be presented with + # a decision. - render :conflict, status: :ok + # Up to 3 characters can be removed at the same time + render json: ConflictBlueprint.render(nil, view: :characters, + conflict_characters: conflict_characters, + incoming_character: incoming_character, + incoming_position: character_params[:position]) 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 + # 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 + else + character = GridCharacter.create!(character_params.merge(party_id: party.id, + character_id: incoming_character.id)) + end - render :show, status: :created if @character.save! + render json: GridCharacterBlueprint.render(character, view: :nested), status: :created if character.save! end - end + end - def resolve + def resolve incoming = Character.find(resolve_params[:incoming]) conflicting = resolve_params[:conflicting].map { |id| GridCharacter.find(id) } party = conflicting.first.party @@ -57,46 +57,48 @@ class Api::V1::GridCharactersController < Api::V1::ApiController # 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 + GridCharacter.destroy(existing_character.id) if existing_character - if (incoming.special) - uncap_level = 3 - uncap_level = 5 if incoming.ulb - uncap_level = 4 if incoming.flb + 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 - - def update_uncap_level - @character = GridCharacter.find(character_params[:id]) - - if current_user - if @character.party.user != current_user - render_unauthorized_response - end + uncap_level = 4 + uncap_level = 6 if incoming.ulb + uncap_level = 5 if incoming.flb end - @character.uncap_level = character_params[:uncap_level] - render :show, status: :ok if @character.save! - end + character = GridCharacter.create!(party_id: party.id, character_id: incoming.id, + position: resolve_params[:position], uncap_level: uncap_level) + render json: GridCharacterBlueprint.render(character, view: :nested), status: :created if character.save! + end - def destroy - end + def update_uncap_level + character = GridCharacter.find(character_params[:id]) - private + render_unauthorized_response if current_user && (character.party.user != current_user) - # Specify whitelisted properties that can be modified. - def character_params - params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level, :conflicting, :incoming) - end + character.uncap_level = character_params[:uncap_level] + return unless character.save! - def resolve_params - params.require(:resolve).permit(:position, :incoming, :conflicting => []) + render json: GridCharacterBlueprint.render(character, view: :nested, root: :grid_character) + end + + # TODO: Implement removing characters + def destroy; end + + private + + # Specify whitelisted properties that can be modified. + def character_params + params.require(:character).permit(:id, :party_id, :character_id, :position, :uncap_level, :conflicting, + :incoming) + end + + def resolve_params + params.require(:resolve).permit(:position, :incoming, conflicting: []) + end end + end end diff --git a/app/controllers/api/v1/grid_summons_controller.rb b/app/controllers/api/v1/grid_summons_controller.rb index 4198e46..cf9ea7d 100644 --- a/app/controllers/api/v1/grid_summons_controller.rb +++ b/app/controllers/api/v1/grid_summons_controller.rb @@ -1,45 +1,45 @@ -class Api::V1::GridSummonsController < Api::V1::ApiController - def create +# frozen_string_literal: true + +module Api + module V1 + class GridSummonsController < Api::V1::ApiController + def create party = Party.find(summon_params[:party_id]) canonical_summon = Summon.find(summon_params[:summon_id]) - - if current_user - if party.user != current_user - render_unauthorized_response - end + + render_unauthorized_response if current_user && (party.user != current_user) + + if (grid_summon = GridSummon.where( + party_id: party.id, + position: summon_params[:position] + ).first) + GridSummon.destroy(grid_summon.id) end - if grid_summon = GridSummon.where( - party_id: party.id, - position: summon_params[:position] - ).first - GridSummon.destroy(grid_summon.id) - end + summon = GridSummon.create!(summon_params.merge(party_id: party.id, summon_id: canonical_summon.id)) + render json: GridSummonBlueprint.render(summon, view: :nested), status: :created if summon.save! + end - @summon = GridSummon.create!(summon_params.merge(party_id: party.id, summon_id: canonical_summon.id)) - render :show, status: :created if @summon.save! - end - - def update_uncap_level - @summon = GridSummon.find(summon_params[:id]) + def update_uncap_level + summon = GridSummon.find(summon_params[:id]) - if current_user - if @summon.party.user != current_user - render_unauthorized_response - end - end + render_unauthorized_response if current_user && (summon.party.user != current_user) - @summon.uncap_level = summon_params[:uncap_level] - render :show, status: :ok if @summon.save! - end + summon.uncap_level = summon_params[:uncap_level] + return unless summon.save! - def destroy - end + render json: GridSummonBlueprint.render(summon, view: :nested, root: :grid_summon) + end - private + # TODO: Implement removing summons + def destroy; end - # Specify whitelisted properties that can be modified. - def summon_params + private + + # Specify whitelisted properties that can be modified. + def summon_params params.require(:summon).permit(:id, :party_id, :summon_id, :position, :main, :friend, :uncap_level) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/api/v1/grid_weapons_controller.rb b/app/controllers/api/v1/grid_weapons_controller.rb index a2dfa7a..3d21caf 100644 --- a/app/controllers/api/v1/grid_weapons_controller.rb +++ b/app/controllers/api/v1/grid_weapons_controller.rb @@ -1,39 +1,35 @@ -class Api::V1::GridWeaponsController < Api::V1::ApiController - before_action :set, except: ['create', 'update_uncap_level', 'destroy'] +# frozen_string_literal: true - def create +module Api + module V1 + class GridWeaponsController < Api::V1::ApiController + before_action :set, except: %w[create update_uncap_level destroy] + + def create party = Party.find(weapon_params[:party_id]) canonical_weapon = Weapon.find(weapon_params[:weapon_id]) - if current_user - if party.user != current_user - render_unauthorized_response - end + render_unauthorized_response if current_user && (party.user != current_user) + + if (grid_weapon = GridWeapon.where( + party_id: party.id, + position: weapon_params[:position] + ).first) + GridWeapon.destroy(grid_weapon.id) end - if grid_weapon = GridWeapon.where( - party_id: party.id, - position: weapon_params[:position] - ).first - GridWeapon.destroy(grid_weapon.id) + weapon = GridWeapon.create!(weapon_params.merge(party_id: party.id, weapon_id: canonical_weapon.id)) + + if weapon.position == -1 + party.element = weapon.weapon.element + party.save! end - @weapon = GridWeapon.create!(weapon_params.merge(party_id: party.id, weapon_id: canonical_weapon.id)) + render json: GridWeaponBlueprint.render(weapon, view: :full), status: :created if weapon.save! + end - if (@weapon.position == -1) - party.element = @weapon.weapon.element - party.save! - end - - render :show, status: :created if @weapon.save! - end - - def update - if current_user - if @weapon.party.user != current_user - render_unauthorized_response - end - end + def update + render_unauthorized_response if current_user && (@weapon.party.user != current_user) # TODO: Server-side validation of weapon mods # We don't want someone modifying the JSON and adding @@ -41,35 +37,39 @@ class Api::V1::GridWeaponsController < Api::V1::ApiController # Maybe we make methods on the model to validate for us somehow - render :update, status: :ok if @weapon.update(weapon_params) - end + render json: GridWeaponBlueprint.render(@weapon, view: :nested) if @weapon.update(weapon_params) + end - def update_uncap_level - @weapon = GridWeapon.find(weapon_params[:id]) + # TODO: Implement removing characters + def destroy; end - if current_user - if party.user != current_user - render_unauthorized_response - end - end + def update_uncap_level + weapon = GridWeapon.find(weapon_params[:id]) - @weapon.uncap_level = weapon_params[:uncap_level] - render :show, status: :ok if @weapon.save! - end + render_unauthorized_response if current_user && (weapon.party.user != current_user) - private + weapon.uncap_level = weapon_params[:uncap_level] + return unless weapon.save! - def set - @weapon = GridWeapon.where("id = ?", params[:id]).first - end + render json: GridWeaponBlueprint.render(weapon, view: :nested, root: :grid_weapon), + status: :created + end - # Specify whitelisted properties that can be modified. - def weapon_params + private + + def set + @weapon = GridWeapon.where('id = ?', params[:id]).first + end + + # Specify whitelisted properties that can be modified. + def weapon_params params.require(:weapon).permit( - :id, :party_id, :weapon_id, - :position, :mainhand, :uncap_level, :element, - :weapon_key1_id, :weapon_key2_id, :weapon_key3_id, - :ax_modifier1, :ax_modifier2, :ax_strength1, :ax_strength2 + :id, :party_id, :weapon_id, + :position, :mainhand, :uncap_level, :element, + :weapon_key1_id, :weapon_key2_id, :weapon_key3_id, + :ax_modifier1, :ax_modifier2, :ax_strength1, :ax_strength2 ) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/api/v1/job_skills_controller.rb b/app/controllers/api/v1/job_skills_controller.rb index 24d519f..8b466a1 100644 --- a/app/controllers/api/v1/job_skills_controller.rb +++ b/app/controllers/api/v1/job_skills_controller.rb @@ -1,13 +1,16 @@ -class Api::V1::JobSkillsController < Api::V1::ApiController - def all - @skills = JobSkill.all() - render :all, status: :ok - end +# frozen_string_literal: true - def job - job = Job.find(params[:id]) +module Api + module V1 + class JobSkillsController < Api::V1::ApiController + def all + render json: JobSkillBlueprint.render(JobSkill.all) + end - @skills = JobSkill.where(job: job).or(JobSkill.where(sub: true)) - render :all, status: :ok + def job + @skills = JobSkill.where('job_id != ? AND emp = ?', params[:id], true) + render json: JobSkillBlueprint.render(@skills) + end end + end end diff --git a/app/controllers/api/v1/jobs_controller.rb b/app/controllers/api/v1/jobs_controller.rb index 74d5a9a..db75319 100644 --- a/app/controllers/api/v1/jobs_controller.rb +++ b/app/controllers/api/v1/jobs_controller.rb @@ -1,160 +1,180 @@ -class Api::V1::JobsController < Api::V1::ApiController - before_action :set, only: %w[update_job update_job_skills] +# frozen_string_literal: true - def all - @jobs = Job.all() - render :all, status: :ok - end +module Api + module V1 + class JobsController < Api::V1::ApiController + before_action :set, only: %w[update_job update_job_skills] - def update_job - raise NoJobProvidedError unless job_params[:job_id].present? - - # Extract job and find its main skills - job = Job.find(job_params[:job_id]) - main_skills = JobSkill.where(job: job.id, main: true) - - # Update the party - @party.job = job - main_skills.each_with_index do |skill, index| - @party["skill#{index}_id"] = skill.id - end - - # Check for incompatible Base and EMP skills - %w[skill1_id skill2_id skill3_id].each do |key| - @party[key] = nil if @party[key] && mismatched_skill(@party.job, JobSkill.find(@party[key])) - end - - render :update, status: :ok if @party.save! - end - - def update_job_skills - throw NoJobSkillProvidedError unless job_params[:skill1_id] || job_params[:skill2_id] || job_params[:skill3_id] - - # Determine which incoming keys contain new skills - skill_keys = %w[skill1_id skill2_id skill3_id] - new_skill_keys = job_params.keys.select { |key| skill_keys.include?(key) } - - # If there are new skills, merge them with the existing skills - unless new_skill_keys.empty? - existing_skills = { - 1 => @party.skill1, - 2 => @party.skill2, - 3 => @party.skill3 - } - - new_skill_ids = new_skill_keys.map { |key| job_params[key] } - new_skill_ids.map do |id| - skill = JobSkill.find(id) - raise Api::V1::IncompatibleSkillError.new(job: @party.job, skill: skill) if mismatched_skill(@party.job, skill) + def all + render json: JobBlueprint.render(Job.all) end - positions = extract_positions_from_keys(new_skill_keys) - new_skills = merge_skills_with_existing_skills(existing_skills, new_skill_ids, positions) + def update_job + if job_params[:job_id] != -1 + # Extract job and find its main skills + old_job = @party.job + job = Job.find(job_params[:job_id]) + main_skills = JobSkill.where(job: job.id, main: true) - new_skill_ids = new_skills.each_with_object({}) do |(index, skill), memo| - memo["skill#{index}_id"] = skill.id if skill + # Update the party + @party.job = job + main_skills.each_with_index do |skill, index| + @party["skill#{index}_id"] = skill.id + end + + # Check for incompatible Base and EMP skills + %w[skill1_id skill2_id skill3_id].each do |key| + @party[key] = nil if @party[key] && mismatched_skill(@party.job, JobSkill.find(@party[key])) + end + + # Remove extra subskills if necessary + if old_job && + %w[1 2 3].include?(old_job.row) && + %w[4 5 ex2].include?(job.row) && + @party.skill1 && @party.skill2 && @party.skill3 && + @party.skill1.sub && @party.skill2.sub && @party.skill3.sub + @party['skill3_id'] = nil + end + else + @party.job = nil + %w[skill0_id skill1_id skill2_id skill3_id].each do |key| + @party[key] = nil + end + end + + render json: PartyBlueprint.render(@party, view: :jobs) if @party.save! end - @party.attributes = new_skill_ids - end + def update_job_skills + throw NoJobSkillProvidedError unless job_params[:skill1_id] || job_params[:skill2_id] || job_params[:skill3_id] - render :update, status: :ok if @party.save! - end + # Determine which incoming keys contain new skills + skill_keys = %w[skill1_id skill2_id skill3_id] + new_skill_keys = job_params.keys.select { |key| skill_keys.include?(key) } - private + # If there are new skills, merge them with the existing skills + unless new_skill_keys.empty? + existing_skills = { + 1 => @party.skill1, + 2 => @party.skill2, + 3 => @party.skill3 + } - def merge_skills_with_existing_skills( - existing_skills, - new_skill_ids, - positions - ) - new_skills = new_skill_ids.map { |id| JobSkill.find(id) } + new_skill_ids = new_skill_keys.map { |key| job_params[key] } + new_skill_ids.map do |id| + skill = JobSkill.find(id) + raise Api::V1::IncompatibleSkillError.new(job: @party.job, skill: skill) if mismatched_skill(@party.job, + skill) + end - new_skills.each_with_index do |skill, index| - existing_skills = place_skill_in_existing_skills(existing_skills, skill, positions[index]) - end + positions = extract_positions_from_keys(new_skill_keys) + new_skills = merge_skills_with_existing_skills(existing_skills, new_skill_ids, positions) - existing_skills - end + new_skill_ids = new_skills.each_with_object({}) do |(index, skill), memo| + memo["skill#{index}_id"] = skill.id if skill + end - def place_skill_in_existing_skills(existing_skills, skill, position) - # Test if skill will exceed allowances of skill types - skill_type = skill.sub ? 'sub' : 'emp' + @party.attributes = new_skill_ids + end - unless can_add_skill_of_type(existing_skills, position, skill_type) - raise Api::V1::TooManySkillsOfTypeError.new(skill_type: skill_type) - end + render json: PartyBlueprint.render(@party, view: :jobs) if @party.save! + end - if !existing_skills[position] - existing_skills[position] = skill - else - value = existing_skills.compact.detect { |_, value| value && value.id == skill.id } - old_position = existing_skills.key(value[1]) if value + private - if old_position - existing_skills = swap_skills_at_position(existing_skills, skill, position, old_position) - else - existing_skills[position] = skill + def merge_skills_with_existing_skills( + existing_skills, + new_skill_ids, + positions + ) + new_skills = new_skill_ids.map { |id| JobSkill.find(id) } + + new_skills.each_with_index do |skill, index| + existing_skills = place_skill_in_existing_skills(existing_skills, skill, positions[index]) + end + + existing_skills + end + + def place_skill_in_existing_skills(existing_skills, skill, position) + # Test if skill will exceed allowances of skill types + skill_type = skill.sub ? 'sub' : 'emp' + + unless can_add_skill_of_type(existing_skills, position, skill_type) + raise Api::V1::TooManySkillsOfTypeError.new(skill_type: skill_type) + end + + if !existing_skills[position] + existing_skills[position] = skill + else + value = existing_skills.compact.detect { |_, value| value && value.id == skill.id } + old_position = existing_skills.key(value[1]) if value + + if old_position + existing_skills = swap_skills_at_position(existing_skills, skill, position, old_position) + else + existing_skills[position] = skill + end + end + + existing_skills + end + + def swap_skills_at_position(skills, new_skill, position1, position2) + # Check desired position for a skill + displaced_skill = skills[position1] if skills[position1].present? + + # Put skill in new position + skills[position1] = new_skill + skills[position2] = displaced_skill + + skills + end + + def extract_positions_from_keys(keys) + # Subtract by 1 because we won't operate on the 0th skill, so we don't pass it + keys.map { |key| key['skill'.length].to_i } + end + + def can_add_skill_of_type(skills, position, type) + if %w[4 5 ex2].include?(@party.job.row) && skills.values.compact.length.positive? + max_skill_of_type = 2 + skills_to_check = skills.compact.reject { |key, _| key == position } + + sum = skills_to_check.values.count { |value| value.send(type) } + return sum + 1 <= max_skill_of_type + end + + true + end + + def mismatched_skill(job, skill) + mismatched_main = (skill.job.id != job.id) && skill.main && !skill.sub + mismatched_emp = (skill.job.id != job.id) && skill.emp + mismatched_base = skill.job.base_job && (job.row != 'ex2' || skill.job.base_job.id != job.base_job.id) && skill.base + + if %w[4 5 ex2].include?(job.row) + true if mismatched_emp || mismatched_base || mismatched_main + elsif mismatched_emp || mismatched_main + true + else + false + end + end + + def set + @party = Party.where('id = ?', params[:id]).first + end + + def job_params + params.require(:party).permit( + :job_id, + :skill0_id, + :skill1_id, + :skill2_id, + :skill3_id + ) end end - - existing_skills - end - - def swap_skills_at_position(skills, new_skill, position1, position2) - # Check desired position for a skill - displaced_skill = skills[position1] if skills[position1].present? - - # Put skill in new position - skills[position1] = new_skill - skills[position2] = displaced_skill - - skills - end - - def extract_positions_from_keys(keys) - # Subtract by 1 because we won't operate on the 0th skill, so we don't pass it - keys.map { |key| key['skill'.length].to_i } - end - - def can_add_skill_of_type(skills, position, type) - if skills.values.compact.length.positive? - max_skill_of_type = 2 - skills_to_check = skills.compact.reject { |key, _| key == position } - - sum = skills_to_check.values.count { |value| value.send(type) } - - sum + 1 <= max_skill_of_type - else - true - end - end - - def mismatched_skill(job, skill) - mismatched_main = (skill.job.id != job.id) && skill.main && !skill.sub - mismatched_emp = (skill.job.id != job.id) && skill.emp - mismatched_base = skill.job.base_job && (job.row != 'ex2' || skill.job.base_job.id != job.base_job.id) && skill.base - - if %w[4 5 ex2].include?(job.row) - true if mismatched_emp || mismatched_base || mismatched_main - elsif mismatched_emp || mismatched_main - true - else - false - end - end - - def set - @party = Party.where('id = ?', params[:id]).first - end - - def job_params - params.require(:party).permit( - :job_id, - :skill0_id, - :skill1_id, - :skill2_id, - :skill3_id - ) end end diff --git a/app/controllers/api/v1/parties_controller.rb b/app/controllers/api/v1/parties_controller.rb index 9ed82f9..d97b96f 100644 --- a/app/controllers/api/v1/parties_controller.rb +++ b/app/controllers/api/v1/parties_controller.rb @@ -1,162 +1,150 @@ -class Api::V1::PartiesController < Api::V1::ApiController - before_action :set_from_slug, - except: %w[create destroy update index favorites] - before_action :set, only: %w[update destroy] +# frozen_string_literal: true - def create - @party = Party.new(shortcode: random_string) - @party.extra = party_params['extra'] +module Api + module V1 + PER_PAGE = 15 - job = Job.find(party_params['job_id']) if party_params['job_id'].present? - if job - job_skills = JobSkill.where(job: job.id, main: true) - job_skills.each_with_index do |skill, index| - @party["skill#{index}_id"] = skill.id + class PartiesController < Api::V1::ApiController + before_action :set_from_slug, + except: %w[create destroy update index favorites] + before_action :set, only: %w[update destroy] + + def create + @party = Party.new(shortcode: random_string) + @party.extra = party_params['extra'] + + # TODO: Extract this into a different method + job = Job.find(party_params['job_id']) if party_params['job_id'].present? + if job + job_skills = JobSkill.where(job: job.id, main: true) + job_skills.each_with_index do |skill, index| + @party["skill#{index}_id"] = skill.id + end + end + + @party.user = current_user if current_user + + if @party.save! + return render json: PartyBlueprint.render(@party, view: :full, root: :party), + status: :created + end + + render_validation_error_response(@party) + end + + def show + return render json: PartyBlueprint.render(@party, view: :full, root: :party) if @party + + render_not_found_response('project') + end + + def update + render_unauthorized_response if @party.user != current_user + + @party.attributes = party_params.except(:skill1_id, :skill2_id, :skill3_id) + + return render json: PartyBlueprint.render(@party, view: :full, root: :party) if @party.save! + + render_validation_error_response(@party) + end + + def destroy + render_unauthorized_response if @party.user != current_user + return render json: PartyBlueprint.render(@party, view: :destroyed, root: :checkin) if @party.destroy + end + + def index + conditions = build_conditions(request.params) + ap conditions + + @parties = Party.where(conditions) + .order(created_at: :desc) + .paginate(page: request.params[:page], per_page: PER_PAGE) + .each { |party| party.favorited = current_user ? party.is_favorited(current_user) : false } + + count = Party.where(conditions).count + total_pages = count.to_f / PER_PAGE > 1 ? (count.to_f / PER_PAGE).ceil : 1 + + render json: PartyBlueprint.render(@parties, + view: :collection, + root: :results, + meta: { + count: count, + total_pages: total_pages, + per_page: PER_PAGE + }) + end + + def favorites + raise Api::V1::UnauthorizedError unless current_user + + conditions = build_conditions(request.params) + conditions[:favorites] = { user_id: current_user.id } + + @parties = Party.joins(:favorites) + .where(conditions) + .order('favorites.created_at DESC') + .paginate(page: request.params[:page], per_page: PER_PAGE) + .each { |party| party.favorited = party.is_favorited(current_user) } + + count = Party.joins(:favorites).where(conditions).count + total_pages = count.to_f / PER_PAGE > 1 ? (count.to_f / PER_PAGE).ceil : 1 + + render json: PartyBlueprint.render(@parties, + view: :collection, + root: :results, + meta: { + count: count, + total_pages: total_pages, + per_page: PER_PAGE + }) + end + + private + + def build_conditions(params) + unless params['recency'].blank? + start_time = (DateTime.current - params['recency'].to_i.seconds) + .to_datetime.beginning_of_day + end + + {}.tap do |hash| + hash[:element] = params['element'] unless params['element'].blank? + hash[:raid] = params['raid'] unless params['raid'].blank? + hash[:created_at] = start_time..DateTime.current unless params['recency'].blank? + hash[:weapons_count] = 5..13 + 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 + end + + def set + @party = Party.where('id = ?', params[:id]).first + end + + def party_params + params.require(:party).permit( + :user_id, + :extra, + :name, + :description, + :raid_id, + :job_id, + :skill0_id, + :skill1_id, + :skill2_id, + :skill3_id + ) end end - - @party.user = current_user if current_user - - render :show, status: :created if @party.save! - end - - def show - render_not_found_response if @party.nil? - end - - def update - if @party.user != current_user - render_unauthorized_response - else - @party.attributes = party_params.except(:skill1_id, :skill2_id, :skill3_id) - end - - render :update, status: :ok if @party.save! - end - - def index - @per_page = 15 - - now = DateTime.current - start_time = - ( - now - request.params["recency"].to_i.seconds - ).to_datetime.beginning_of_day unless request.params["recency"].blank? - - conditions = {} - conditions[:element] = request.params["element"] unless request.params[ - "element" - ].blank? - conditions[:raid] = request.params["raid"] unless request.params[ - "raid" - ].blank? - conditions[:created_at] = start_time..now unless request.params[ - "recency" - ].blank? - conditions[:weapons_count] = 5..13 - - @parties = - Party - .where(conditions) - .order(created_at: :desc) - .paginate(page: request.params[:page], per_page: @per_page) - .each do |party| - party.favorited = - current_user ? party.is_favorited(current_user) : false - end - @count = Party.where(conditions).count - - render :all, status: :ok - end - - def favorites - raise Api::V1::UnauthorizedError unless current_user - - @per_page = 15 - - now = DateTime.current - start_time = - ( - now - params["recency"].to_i.seconds - ).to_datetime.beginning_of_day unless request.params["recency"].blank? - - conditions = {} - conditions[:element] = request.params["element"] unless request.params[ - "element" - ].blank? - conditions[:raid] = request.params["raid"] unless request.params[ - "raid" - ].blank? - conditions[:created_at] = start_time..now unless request.params[ - "recency" - ].blank? - conditions[:favorites] = { user_id: current_user.id } - - @parties = - Party - .joins(:favorites) - .where(conditions) - .order("favorites.created_at DESC") - .paginate(page: request.params[:page], per_page: @per_page) - .each { |party| party.favorited = party.is_favorited(current_user) } - @count = Party.joins(:favorites).where(conditions).count - - render :all, status: :ok - end - - def destroy - if @party.user != current_user - render_unauthorized_response - elsif @party.destroy - render :destroyed, status: :ok - end - end - - def weapons - render_not_found_response if @party.nil? - render :weapons, status: :ok - end - - def summons - render_not_found_response if @party.nil? - render :summons, status: :ok - end - - def characters - render_not_found_response if @party.nil? - render :characters, status: :ok - end - - private - - def random_string - numChars = 6 - o = [("a".."z"), ("A".."Z"), (0..9)].map(&:to_a).flatten - return (0...numChars).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 - end - - def set - @party = Party.where("id = ?", params[:id]).first - end - - def party_params - params.require(:party).permit( - :user_id, - :extra, - :name, - :description, - :raid_id, - :job_id, - :skill0_id, - :skill1_id, - :skill2_id, - :skill3_id - ) end end diff --git a/app/controllers/api/v1/raids_controller.rb b/app/controllers/api/v1/raids_controller.rb index cac3b93..f5b898e 100644 --- a/app/controllers/api/v1/raids_controller.rb +++ b/app/controllers/api/v1/raids_controller.rb @@ -1,6 +1,11 @@ -class Api::V1::RaidsController < Api::V1::ApiController - def all - @raids = Raid.all() - render :all, status: :ok +# frozen_string_literal: true + +module Api + module V1 + class RaidsController < Api::V1::ApiController + def all + render json: RaidBlueprint.render(Raid.all) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index 9f42fc6..a383525 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -1,139 +1,194 @@ -class Api::V1::SearchController < Api::V1::ApiController - def characters - filters = search_params[:filters] - locale = search_params[:locale] || 'en' - conditions = {} +# frozen_string_literal: true - if filters - conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? - conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? - conditions[:proficiency1] = filters['proficiency1'] unless filters['proficiency1'].blank? || filters['proficiency1'].empty? - conditions[:proficiency2] = filters['proficiency2'] unless filters['proficiency2'].blank? || filters['proficiency2'].empty? - # conditions[:series] = filters['series'] unless filters['series'].blank? || filters['series'].empty? - end +module Api + module V1 + PER_PAGE = 10 - @characters = if search_params[:query].present? && search_params[:query].length >= 2 + class SearchController < Api::V1::ApiController + def characters + filters = search_params[:filters] + locale = search_params[:locale] || 'en' + conditions = {} + + if filters + conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? + conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? + unless filters['proficiency1'].blank? || filters['proficiency1'].empty? + conditions[:proficiency1] = + filters['proficiency1'] + end + unless filters['proficiency2'].blank? || filters['proficiency2'].empty? + conditions[:proficiency2] = + filters['proficiency2'] + end + # conditions[:series] = filters['series'] unless filters['series'].blank? || filters['series'].empty? + end + + characters = if search_params[:query].present? && search_params[:query].length >= 2 + if locale == 'ja' + Character.jp_search(search_params[:query]).where(conditions) + else + Character.en_search(search_params[:query]).where(conditions) + end + else + Character.where(conditions) + end + + count = characters.length + paginated = characters.paginate(page: search_params[:page], per_page: PER_PAGE) + + render json: CharacterBlueprint.render(paginated, + root: :results, + meta: { + count: count, + total_pages: total_pages(count), + per_page: PER_PAGE + }) + end + + def weapons + filters = search_params[:filters] + locale = search_params[:locale] || 'en' + conditions = {} + + if filters + conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? + conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? + unless filters['proficiency1'].blank? || filters['proficiency1'].empty? + conditions[:proficiency] = + filters['proficiency1'] + end + conditions[:series] = filters['series'] unless filters['series'].blank? || filters['series'].empty? + end + + weapons = if search_params[:query].present? && search_params[:query].length >= 2 if locale == 'ja' - Character.jp_search(search_params[:query]).where(conditions) + Weapon.jp_search(search_params[:query]).where(conditions) else - Character.en_search(search_params[:query]).where(conditions) + Weapon.en_search(search_params[:query]).where(conditions) end else - Character.where(conditions) + Weapon.where(conditions) end - @count = @characters.length - @characters = @characters.paginate(page: search_params[:page], per_page: 10) - end + count = weapons.length + paginated = weapons.paginate(page: search_params[:page], per_page: PER_PAGE) - def weapons - filters = search_params[:filters] - locale = search_params[:locale] || 'en' - conditions = {} + render json: WeaponBlueprint.render(paginated, + root: :results, + meta: { + count: count, + total_pages: total_pages(count), + per_page: PER_PAGE + }) + end - if filters - conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? - conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? - conditions[:proficiency] = filters['proficiency1'] unless filters['proficiency1'].blank? || filters['proficiency1'].empty? - conditions[:series] = filters['series'] unless filters['series'].blank? || filters['series'].empty? - end + def summons + filters = search_params[:filters] + locale = search_params[:locale] || 'en' + conditions = {} - @weapons = if search_params[:query].present? && search_params[:query].length >= 2 - if locale == 'ja' - Weapon.jp_search(search_params[:query]).where(conditions) + if filters + conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? + conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? + end + + summons = if search_params[:query].present? && search_params[:query].length >= 2 + if locale == 'ja' + Summon.jp_search(search_params[:query]).where(conditions) + else + Summon.en_search(search_params[:query]).where(conditions) + end + else + Summon.where(conditions) + end + + count = summons.length + paginated = summons.paginate(page: search_params[:page], per_page: PER_PAGE) + + render json: SummonBlueprint.render(paginated, + root: :results, + meta: { + count: count, + total_pages: total_pages(count), + per_page: PER_PAGE + }) + end + + def job_skills + raise Api::V1::NoJobProvidedError unless search_params[:job].present? + + # Set up basic parameters we'll use + job = Job.find(search_params[:job]) + locale = search_params[:locale] || 'en' + + # Set the conditions based on the group requested + conditions = {} + if search_params[:filters].present? && search_params[:filters]['group'].present? + group = search_params[:filters]['group'].to_i + + if group >= 0 && group < 4 + conditions[:color] = group + conditions[:emp] = false + conditions[:base] = false + elsif group == 4 + conditions[:emp] = true + elsif group == 5 + conditions[:base] = true + end + end + + # Perform the query + skills = if search_params[:query].present? && search_params[:query].length >= 2 + JobSkill.method("#{locale}_search").call(search_params[:query]) + .where(conditions) + .where(job: job.id, main: false) + .or( + JobSkill.method("#{locale}_search").call(search_params[:query]) + .where(conditions) + .where(sub: true) + .where.not(job: job.id) + ) else - Weapon.en_search(search_params[:query]).where(conditions) + JobSkill.all + .where(conditions) + .where(job: job.id, main: false) + .or( + JobSkill.all + .where(conditions) + .where(sub: true) + .where.not(job: job.id) + ) + .or( + JobSkill.all + .where(conditions) + .where(job: job.base_job.id, base: true) + .where.not(job: job.id) + ) end - else - Weapon.where(conditions) - end - @count = @weapons.length - @weapons = @weapons.paginate(page: search_params[:page], per_page: 10) - end + count = skills.length + paginated = skills.paginate(page: search_params[:page], per_page: PER_PAGE) - def summons - filters = search_params[:filters] - locale = search_params[:locale] || 'en' - conditions = {} + render json: JobSkillBlueprint.render(paginated, + root: :results, + meta: { + count: count, + total_pages: total_pages(count), + per_page: PER_PAGE + }) + end - if filters - conditions[:rarity] = filters['rarity'] unless filters['rarity'].blank? || filters['rarity'].empty? - conditions[:element] = filters['element'] unless filters['element'].blank? || filters['element'].empty? - end + private - @summons = if search_params[:query].present? && search_params[:query].length >= 2 - if locale == 'ja' - Summon.jp_search(search_params[:query]).where(conditions) - else - Summon.en_search(search_params[:query]).where(conditions) - end - else - Summon.where(conditions) - end + def total_pages(count) + count.to_f / PER_PAGE > 1 ? (count.to_f / PER_PAGE).ceil : 1 + end - @count = @summons.length - @summons = @summons.paginate(page: search_params[:page], per_page: 10) - end - - def job_skills - raise Api::V1::NoJobProvidedError unless search_params[:job].present? - - # Set up basic parameters we'll use - job = Job.find(search_params[:job]) - locale = search_params[:locale] || 'en' - - # Set the conditions based on the group requested - conditions = {} - if search_params[:filters].present? && search_params[:filters]['group'].present? - group = search_params[:filters]['group'].to_i - - if group >= 0 && group < 4 - conditions[:color] = group - conditions[:emp] = false - conditions[:base] = false - elsif group == 4 - conditions[:emp] = true - elsif group == 5 - conditions[:base] = true + # Specify whitelisted properties that can be modified. + def search_params + params.require(:search).permit! end end - - # Perform the query - @skills = if search_params[:query].present? && search_params[:query].length >= 2 - JobSkill.method("#{locale}_search").call(search_params[:query]) - .where(conditions) - .where(job: job.id, main: false) - .or( - JobSkill.method("#{locale}_search").call(search_params[:query]) - .where(conditions) - .where(sub: true) - ) - else - JobSkill.all - .where(conditions) - .where(job: job.id, main: false) - .or( - JobSkill.all - .where(conditions) - .where(sub: true) - ) - .or( - JobSkill.all - .where(conditions) - .where(job: job.base_job.id, base: true) - .where.not(job: job.id) - ) - end - - @count = @skills.length - @skills = @skills.paginate(page: search_params[:page], per_page: 10) - end - - private - - # Specify whitelisted properties that can be modified. - def search_params - params.require(:search).permit! end end diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index a7340e5..267e23f 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,103 +1,113 @@ -class Api::V1::UsersController < Api::V1::ApiController - class ForbiddenError < StandardError; end +# frozen_string_literal: true - before_action :set, except: ['create', 'check_email', 'check_username'] - before_action :set_by_id, only: ['info', 'update'] +module Api + module V1 + PER_PAGE = 15 - def create - @user = User.new(user_params) + class UsersController < Api::V1::ApiController + class ForbiddenError < StandardError; end - token = Doorkeeper::AccessToken.create!( + before_action :set, except: %w[create check_email check_username] + before_action :set_by_id, only: %w[info update] + + def create + user = User.new(user_params) + + if user.save! + token = Doorkeeper::AccessToken.create!( application_id: nil, - resource_owner_id: @user.id, + resource_owner_id: user.id, expires_in: 30.days, scopes: 'public' - ).token + ).token - if @user.save! - @presenter = { - user_id: @user.id, - username: @user.username, - token: token - } - - render :create, status: :created - end - end - - - def update - render :info, status: :ok if @user.update(user_params) - end - - def info - render :info, status: :ok - end - - def show - if @user - @per_page = 15 - - now = DateTime.current - start_time = (now - params['recency'].to_i.seconds).to_datetime.beginning_of_day unless request.params['recency'].blank? - - conditions = {} - conditions[:element] = request.params['element'] unless request.params['element'].blank? - conditions[:raid] = request.params['raid'] unless request.params['raid'].blank? - conditions[:created_at] = start_time..now unless request.params['recency'].blank? - conditions[:user_id] = @user.id - - @parties = Party - .where(conditions) - .order(created_at: :desc) - .paginate(page: request.params[:page], per_page: @per_page) - .each { |party| - party.favorited = (current_user) ? party.is_favorited(current_user) : false - } - @count = Party.where(conditions).count - else - render_not_found_response - end - end - - def check_email - if params[:email].present? - @available = User.where("email = ?", params[:email]).count == 0 - else - @available = false + return render json: UserBlueprint.render({ + id: user.id, + username: user.username, + token: token + }, + view: :token), + status: :created end - render :available - end + render_validation_error_response(@user) + end - def check_username - if params[:username].present? - @available = User.where("username = ?", params[:username]).count == 0 - else - @available = false + def update + render json: UserBlueprint.render(@user, view: :minimal) if @user.update(user_params) + end + + def info + render json: UserBlueprint.render(@user, view: :minimal) + end + + def show + render_not_found_response('user') unless @user + + conditions = build_conditions(request.params) + conditions[:user_id] = @user.id + + parties = Party + .where(conditions) + .order(created_at: :desc) + .paginate(page: request.params[:page], per_page: PER_PAGE) + .each do |party| + party.favorited = current_user ? party.is_favorited(current_user) : false end - render :available - end + count = Party.where(conditions).count - def destroy - end + render json: UserBlueprint.render(@user, + view: :profile, + root: 'profile', + parties: parties, + meta: { + count: count, + total_pages: count.to_f / PER_PAGE > 1 ? (count.to_f / PER_PAGE).ceil : 1, + per_page: PER_PAGE + }) + end - private + def check_email + render json: EmptyBlueprint.render_as_json(nil, email: params[:email], availability: true) + end - # Specify whitelisted properties that can be modified. - def set - @user = User.where("username = ?", params[:id]).first - end + def check_username + render json: EmptyBlueprint.render_as_json(nil, username: params[:username], availability: true) + end - def set_by_id - @user = User.where("id = ?", params[:id]).first - end + def destroy; end - def user_params + private + + def build_conditions(params) + unless params['recency'].blank? + start_time = (DateTime.current - params['recency'].to_i.seconds) + .to_datetime.beginning_of_day + end + + {}.tap do |hash| + hash[:element] = params['element'] unless params['element'].blank? + hash[:raid] = params['raid'] unless params['raid'].blank? + hash[:created_at] = start_time..DateTime.current unless params['recency'].blank? + end + end + + # Specify whitelisted properties that can be modified. + def set + @user = User.where('username = ?', params[:id]).first + end + + def set_by_id + @user = User.where('id = ?', params[:id]).first + end + + def user_params params.require(:user).permit( - :username, :email, :password, :password_confirmation, - :granblue_id, :picture, :element, :language, :gender, :private + :username, :email, :password, :password_confirmation, + :granblue_id, :picture, :element, :language, :gender, :private ) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/api/v1/weapon_keys_controller.rb b/app/controllers/api/v1/weapon_keys_controller.rb index b51ae6d..1d7e261 100644 --- a/app/controllers/api/v1/weapon_keys_controller.rb +++ b/app/controllers/api/v1/weapon_keys_controller.rb @@ -1,11 +1,19 @@ -class Api::V1::WeaponKeysController < Api::V1::ApiController - def all - conditions = {} - conditions[:series] = request.params['series'] - conditions[:slot] = request.params['slot'] - conditions[:group] = request.params['group'] unless request.params['group'].blank? +# frozen_string_literal: true - @keys = WeaponKey.where(conditions) - render :all, status: :ok +module Api + module V1 + class WeaponKeysController < Api::V1::ApiController + def all + conditions = {}.tap do |hash| + hash[:series] = request.params['series'] + hash[:slot] = request.params['slot'] + hash[:group] = request.params['group'] unless request.params['group'].blank? + end + + render json: WeaponKeyBlueprint.render( + WeaponKey.where(conditions) + ) + end end -end \ No newline at end of file + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ed40efb..13c271f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,4 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::API - # Not usually required for Rails 5 in API mode, but - # necessary here because we're using RABL. - include ActionView::Rendering - append_view_path "#{Rails.root}/app/views" end diff --git a/app/controllers/tokens_controller.rb b/app/controllers/tokens_controller.rb index b61b6ca..b78ba70 100644 --- a/app/controllers/tokens_controller.rb +++ b/app/controllers/tokens_controller.rb @@ -1,36 +1,40 @@ +# frozen_string_literal: true + class TokensController < Doorkeeper::TokensController - # Overriding create action - # POST /oauth/token - def create - response = strategy.authorize - body = response.body + # Overriding create action + # POST /oauth/token + def create + response = strategy.authorize + body = response.body - if response.status == :ok - # User the resource_owner_id from token to identify the user - user = User.find(response.token.resource_owner_id) rescue nil + if response.status == :ok + # User the resource_owner_id from token to identify the user + user = begin + User.find(response.token.resource_owner_id) + rescue StandardError + nil + end - unless user.nil? - ### If you want to render user with template - ### create an ActionController to render out the user - # ac = ActionController::Base.new() - # user_json = ac.render_to_string( template: 'api/users/me', locals: { user: user}) - # body[:user] = Oj.load(user_json) + unless user.nil? + ### If you want to render user with template + ### create an ActionController to render out the user + # ac = ActionController::Base.new() + # user_json = ac.render_to_string( template: 'api/users/me', locals: { user: user}) + # body[:user] = Oj.load(user_json) - ### Or if you want to just append user using 'as_json' - body[:user] = { - id: user.id, - username: user.username - } + ### Or if you want to just append user using 'as_json' + body[:user] = { + id: user.id, + username: user.username + } - end - end - - self.headers.merge! response.headers - self.response_body = body.to_json - self.status = response.status - - rescue Doorkeeper::Errors::DoorkeeperError => e - handle_token_exception e + end end + + headers.merge! response.headers + self.response_body = body.to_json + self.status = response.status + rescue Doorkeeper::Errors::DoorkeeperError => e + handle_token_exception e + end end - \ No newline at end of file diff --git a/app/errors/api/v1/FavoriteAlreadyExistsError.rb b/app/errors/api/v1/FavoriteAlreadyExistsError.rb deleted file mode 100644 index e0ac7b7..0000000 --- a/app/errors/api/v1/FavoriteAlreadyExistsError.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Api::V1 - class FavoriteAlreadyExistsError < GranblueError - def http_status - 422 - end - - def code - "favorite_already_exists" - end - - def message - "This user has favorited this party already" - end - - def to_hash - { - message: message, - code: code - } - end - end -end diff --git a/app/errors/api/v1/IncompatibleSkillError.rb b/app/errors/api/v1/IncompatibleSkillError.rb deleted file mode 100644 index bd8c808..0000000 --- a/app/errors/api/v1/IncompatibleSkillError.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Api::V1 - class IncompatibleSkillError < GranblueError - def initialize(data) - @data = data - end - - def http_status - 422 - end - - def code - 'incompatible_skill' - end - - def message - 'The selected skill cannot be added to the current job' - end - - def to_hash - ap @data - { - message: message, - code: code, - job: @data[:job], - skill: @data[:skill] - } - end - end -end diff --git a/app/errors/api/v1/NoJobProvidedError.rb b/app/errors/api/v1/NoJobProvidedError.rb deleted file mode 100644 index c27f48a..0000000 --- a/app/errors/api/v1/NoJobProvidedError.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Api::V1 - class NoJobProvidedError < GranblueError - def http_status - 422 - end - - def code - "no_job_provided" - end - - def message - "A job ID must be provided" - end - - def to_hash - { - message: message, - code: code - } - end - end -end diff --git a/app/errors/api/v1/NoJobSkillProvidedError.rb b/app/errors/api/v1/NoJobSkillProvidedError.rb deleted file mode 100644 index 60ad888..0000000 --- a/app/errors/api/v1/NoJobSkillProvidedError.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Api::V1 - class NoJobSkillProvidedError < GranblueError - def http_status - 422 - end - - def code - "no_job_skill_provided" - end - - def message - "A job skill ID must be provided" - end - - def to_hash - { - message: message, - code: code - } - end - end -end diff --git a/app/errors/api/v1/UnauthorizedError.rb b/app/errors/api/v1/UnauthorizedError.rb deleted file mode 100644 index 842c178..0000000 --- a/app/errors/api/v1/UnauthorizedError.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Api::V1 - class UnauthorizedError < StandardError - def http_status - 401 - end - - def code - "unauthorized" - end - - def message - "User is not allowed to modify that resource" - end - - def to_hash - { - message: message, - code: code - } - end - end -end diff --git a/app/errors/api/v1/favorite_already_exists_error.rb b/app/errors/api/v1/favorite_already_exists_error.rb new file mode 100644 index 0000000..cd49d95 --- /dev/null +++ b/app/errors/api/v1/favorite_already_exists_error.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Api + module V1 + class FavoriteAlreadyExistsError < GranblueError + def http_status + 422 + end + + def code + 'favorite_already_exists' + end + + def message + 'This user has favorited this party already' + end + + def to_hash + { + message: message, + code: code + } + end + end + end +end diff --git a/app/errors/api/v1/GranblueError.rb b/app/errors/api/v1/granblue_error.rb similarity index 93% rename from app/errors/api/v1/GranblueError.rb rename to app/errors/api/v1/granblue_error.rb index dec43a1..e2d0c70 100644 --- a/app/errors/api/v1/GranblueError.rb +++ b/app/errors/api/v1/granblue_error.rb @@ -4,7 +4,7 @@ module Api module V1 # This is the base error that we inherit from for application errors class GranblueError < StandardError - def initialize(data) + def initialize(data = '') @data = data end diff --git a/app/errors/api/v1/incompatible_skill_error.rb b/app/errors/api/v1/incompatible_skill_error.rb new file mode 100644 index 0000000..6168feb --- /dev/null +++ b/app/errors/api/v1/incompatible_skill_error.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Api + module V1 + class IncompatibleSkillError < GranblueError + def initialize(data) + @data = data + end + + def http_status + 422 + end + + def code + 'incompatible_skill' + end + + def message + 'The selected skill cannot be added to the current job' + end + + def to_hash + ap @data + { + message: message, + code: code, + job: @data[:job], + skill: @data[:skill] + } + end + end + end +end diff --git a/app/errors/api/v1/no_job_provided_error.rb b/app/errors/api/v1/no_job_provided_error.rb new file mode 100644 index 0000000..70579a2 --- /dev/null +++ b/app/errors/api/v1/no_job_provided_error.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Api + module V1 + class NoJobProvidedError < GranblueError + def http_status + 422 + end + + def code + 'no_job_provided' + end + + def message + 'A job ID must be provided' + end + + def to_hash + { + message: message, + code: code + } + end + end + end +end diff --git a/app/errors/api/v1/no_job_skill_provided_error.rb b/app/errors/api/v1/no_job_skill_provided_error.rb new file mode 100644 index 0000000..38b89b8 --- /dev/null +++ b/app/errors/api/v1/no_job_skill_provided_error.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Api + module V1 + class NoJobSkillProvidedError < GranblueError + def http_status + 422 + end + + def code + 'no_job_skill_provided' + end + + def message + 'A job skill ID must be provided' + end + + def to_hash + { + message: message, + code: code + } + end + end + end +end diff --git a/app/errors/api/v1/SameFavoriteUserError.rb b/app/errors/api/v1/same_favorite_user_error.rb similarity index 91% rename from app/errors/api/v1/SameFavoriteUserError.rb rename to app/errors/api/v1/same_favorite_user_error.rb index 6fbcc79..73f95df 100644 --- a/app/errors/api/v1/SameFavoriteUserError.rb +++ b/app/errors/api/v1/same_favorite_user_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Api module V1 class SameFavoriteUserError < GranblueError diff --git a/app/errors/api/v1/TooManySkillsOfTypeError.rb b/app/errors/api/v1/too_many_skills_of_type_error.rb similarity index 100% rename from app/errors/api/v1/TooManySkillsOfTypeError.rb rename to app/errors/api/v1/too_many_skills_of_type_error.rb diff --git a/app/errors/api/v1/unauthorized_error.rb b/app/errors/api/v1/unauthorized_error.rb new file mode 100644 index 0000000..70aea6d --- /dev/null +++ b/app/errors/api/v1/unauthorized_error.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Api + module V1 + class UnauthorizedError < StandardError + def http_status + 401 + end + + def code + 'unauthorized' + end + + def message + 'User is not allowed to modify that resource' + end + + def to_hash + { + message: message, + code: code + } + end + end + end +end diff --git a/app/helpers/validation_error_serializer.rb b/app/helpers/validation_error_serializer.rb index 730f0b6..ad22738 100644 --- a/app/helpers/validation_error_serializer.rb +++ b/app/helpers/validation_error_serializer.rb @@ -1,33 +1,35 @@ +# frozen_string_literal: true + class ValidationErrorSerializer - def initialize(record, field, details) - @record = record - @field = field - @details = details - end + def initialize(record, field, details) + @record = record + @field = field + @details = details + end - def serialize - { - resource: resource, - field: field, - code: code - } - end + def serialize + { + resource: resource, + field: field, + code: code + } + end - private + private - def resource - @record.class.to_s - end + def resource + @record.class.to_s + end - def field - @field.to_s - end + def field + @field.to_s + end - def code - @details[:error].to_s - end + def code + @details[:error].to_s + end - def underscored_resource_name - @record.class.to_s.gsub('::', '').underscore - end -end \ No newline at end of file + def underscored_resource_name + @record.class.to_s.gsub('::', '').underscore + end +end diff --git a/app/helpers/validation_errors_serializer.rb b/app/helpers/validation_errors_serializer.rb index af2affa..820ebd2 100644 --- a/app/helpers/validation_errors_serializer.rb +++ b/app/helpers/validation_errors_serializer.rb @@ -1,16 +1,17 @@ +# frozen_string_literal: true class ValidationErrorsSerializer - attr_reader :record + attr_reader :record - def initialize(record) - @record = record - end + def initialize(record) + @record = record + end - def serialize - record.errors.details.map do |field, details| - details.map do |error_details| - ValidationErrorSerializer.new(record, field, error_details).serialize - end - end.flatten - end -end \ No newline at end of file + def serialize + record.errors.details.map do |field, details| + details.map do |error_details| + ValidationErrorSerializer.new(record, field, error_details).serialize + end + end.flatten + end +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 10a4cba..71fbba5 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end diff --git a/app/models/character.rb b/app/models/character.rb index fd3a1b5..c772471 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -1,94 +1,99 @@ +# frozen_string_literal: true + class Character < ApplicationRecord - include PgSearch::Model + include PgSearch::Model - pg_search_scope :en_search, - against: :name_en, - using: { - trigram: { - threshold: 0.18 - } - } + pg_search_scope :en_search, + against: :name_en, + using: { + trigram: { + threshold: 0.18 + } + } - pg_search_scope :jp_search, - against: :name_jp, - using: { - tsearch: { - prefix: true, - dictionary: "simple" - } - } + pg_search_scope :jp_search, + against: :name_jp, + using: { + tsearch: { + prefix: true, + dictionary: 'simple' + } + } - def display_resource(character) - character.name_en - end + def blueprint + CharacterBlueprint + end - # enum rarities: { - # R: 1, - # SR: 2, - # SSR: 3 - # } + def display_resource(character) + character.name_en + end - # enum elements: { - # Null: 0, - # Wind: 1, - # Fire: 2, - # Water: 3, - # Earth: 4, - # Dark: 5, - # Light: 6 - # } + # enum rarities: { + # R: 1, + # SR: 2, + # SSR: 3 + # } - # enum proficiency1s: { - # Sabre: 1, - # Dagger: 2, - # Axe: 3, - # Spear: 4, - # Bow: 5, - # Staff: 6, - # Melee: 7, - # Harp: 8, - # Gun: 9, - # Katana: 10 - # }, _prefix: "proficiency1" + # enum elements: { + # Null: 0, + # Wind: 1, + # Fire: 2, + # Water: 3, + # Earth: 4, + # Dark: 5, + # Light: 6 + # } - # enum proficiency2s: { - # None: 0, - # Sabre: 1, - # Dagger: 2, - # Axe: 3, - # Spear: 4, - # Bow: 5, - # Staff: 6, - # Melee: 7, - # Harp: 8, - # Gun: 9, - # Katana: 10, - # }, _default: :None, _prefix: "proficiency2" + # enum proficiency1s: { + # Sabre: 1, + # Dagger: 2, + # Axe: 3, + # Spear: 4, + # Bow: 5, + # Staff: 6, + # Melee: 7, + # Harp: 8, + # Gun: 9, + # Katana: 10 + # }, _prefix: "proficiency1" - # enum race1s: { - # Unknown: 0, - # Human: 1, - # Erune: 2, - # Draph: 3, - # Harvin: 4, - # Primal: 5 - # }, _prefix: "race1" + # enum proficiency2s: { + # None: 0, + # Sabre: 1, + # Dagger: 2, + # Axe: 3, + # Spear: 4, + # Bow: 5, + # Staff: 6, + # Melee: 7, + # Harp: 8, + # Gun: 9, + # Katana: 10, + # }, _default: :None, _prefix: "proficiency2" - # enum race2s: { - # Unknown: 0, - # Human: 1, - # Erune: 2, - # Draph: 3, - # Harvin: 4, - # Primal: 5, - # None: 6 - # }, _default: :None, _prefix: "race2" + # enum race1s: { + # Unknown: 0, + # Human: 1, + # Erune: 2, + # Draph: 3, + # Harvin: 4, + # Primal: 5 + # }, _prefix: "race1" - # enum gender: { - # Unknown: 0, - # Male: 1, - # Female: 2, - # "Male/Female": 3 - # } + # enum race2s: { + # Unknown: 0, + # Human: 1, + # Erune: 2, + # Draph: 3, + # Harvin: 4, + # Primal: 5, + # None: 6 + # }, _default: :None, _prefix: "race2" + # enum gender: { + # Unknown: 0, + # Male: 1, + # Female: 2, + # "Male/Female": 3 + # } end diff --git a/app/models/favorite.rb b/app/models/favorite.rb index a074c9a..4c2d235 100644 --- a/app/models/favorite.rb +++ b/app/models/favorite.rb @@ -1,8 +1,14 @@ -class Favorite < ApplicationRecord - belongs_to :user - belongs_to :party +# frozen_string_literal: true - def party - Party.find(self.party_id) - end +class Favorite < ApplicationRecord + belongs_to :user + belongs_to :party + + def party + Party.find(party_id) + end + + def favorite + FavoriteBlueprint + end end diff --git a/app/models/grid_character.rb b/app/models/grid_character.rb index 6ac365c..2e3e16b 100644 --- a/app/models/grid_character.rb +++ b/app/models/grid_character.rb @@ -1,7 +1,13 @@ -class GridCharacter < ApplicationRecord - belongs_to :party +# frozen_string_literal: true - def character - Character.find(self.character_id) - end +class GridCharacter < ApplicationRecord + belongs_to :party + + def character + Character.find(character_id) + end + + def blueprint + GridCharacterBlueprint + end end diff --git a/app/models/grid_summon.rb b/app/models/grid_summon.rb index cf6b177..9857a9b 100644 --- a/app/models/grid_summon.rb +++ b/app/models/grid_summon.rb @@ -1,7 +1,13 @@ -class GridSummon < ApplicationRecord - belongs_to :party +# frozen_string_literal: true - def summon - Summon.find(self.summon_id) - end +class GridSummon < ApplicationRecord + belongs_to :party + + def summon + Summon.find(summon_id) + end + + def blueprint + GridSummonBlueprint + end end diff --git a/app/models/grid_weapon.rb b/app/models/grid_weapon.rb index aed825e..bd97efb 100644 --- a/app/models/grid_weapon.rb +++ b/app/models/grid_weapon.rb @@ -1,21 +1,27 @@ +# frozen_string_literal: true + class GridWeapon < ApplicationRecord - belongs_to :party, - counter_cache: :weapons_count + belongs_to :party, + counter_cache: :weapons_count - 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 - belongs_to :weapon_key3, class_name: 'WeaponKey', foreign_key: :weapon_key3_id, optional: true + 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 + belongs_to :weapon_key3, class_name: 'WeaponKey', foreign_key: :weapon_key3_id, optional: true - def weapon - Weapon.find(self.weapon_id) - end + def weapon + Weapon.find(weapon_id) + end - def weapon_keys - weapon_keys = [] - weapon_keys.push(self.weapon_key1) if self.weapon_key1 != nil - weapon_keys.push(self.weapon_key2) if self.weapon_key2 != nil - weapon_keys.push(self.weapon_key3) if self.weapon_key3 != nil + def weapon_keys + weapon_keys = [] + weapon_keys.push(weapon_key1) unless weapon_key1.nil? + weapon_keys.push(weapon_key2) unless weapon_key2.nil? + weapon_keys.push(weapon_key3) unless weapon_key3.nil? - weapon_keys - end + weapon_keys + end + + def blueprint + GridWeaponBlueprint + end end diff --git a/app/models/job.rb b/app/models/job.rb index bded82e..beb0ce4 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Job < ApplicationRecord belongs_to :party @@ -6,6 +8,10 @@ class Job < ApplicationRecord class_name: 'Job', optional: true + def blueprint + JobBlueprint + end + def display_resource(job) job.name_en end diff --git a/app/models/job_skill.rb b/app/models/job_skill.rb index 3ab1d84..9e0bcd3 100644 --- a/app/models/job_skill.rb +++ b/app/models/job_skill.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class JobSkill < ApplicationRecord alias eql? == @@ -10,8 +12,8 @@ class JobSkill < ApplicationRecord using: { tsearch: { prefix: true, - dictionary: "simple", - }, + dictionary: 'simple' + } } pg_search_scope :jp_search, @@ -19,15 +21,19 @@ class JobSkill < ApplicationRecord using: { tsearch: { prefix: true, - dictionary: "simple", - }, + dictionary: 'simple' + } } + def blueprint + JobSkillBlueprint + end + def display_resource(skill) skill.name_en end - def ==(o) - self.class == o.class && id == o.id + def ==(other) + self.class == other.class && id == other.id end end diff --git a/app/models/party.rb b/app/models/party.rb index 8c6ef3d..c90c0c4 100644 --- a/app/models/party.rb +++ b/app/models/party.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Party < ApplicationRecord ##### ActiveRecord Associations belongs_to :user, optional: true @@ -5,38 +7,38 @@ class Party < ApplicationRecord belongs_to :job, optional: true belongs_to :skill0, - foreign_key: "skill0_id", - class_name: "JobSkill", + foreign_key: 'skill0_id', + class_name: 'JobSkill', optional: true belongs_to :skill1, - foreign_key: "skill1_id", - class_name: "JobSkill", + foreign_key: 'skill1_id', + class_name: 'JobSkill', optional: true belongs_to :skill2, - foreign_key: "skill2_id", - class_name: "JobSkill", + foreign_key: 'skill2_id', + class_name: 'JobSkill', optional: true belongs_to :skill3, - foreign_key: "skill3_id", - class_name: "JobSkill", + foreign_key: 'skill3_id', + class_name: 'JobSkill', optional: true has_many :characters, - foreign_key: "party_id", - class_name: "GridCharacter", + foreign_key: 'party_id', + class_name: 'GridCharacter', dependent: :destroy has_many :weapons, - foreign_key: "party_id", - class_name: "GridWeapon", + foreign_key: 'party_id', + class_name: 'GridWeapon', dependent: :destroy has_many :summons, - foreign_key: "party_id", - class_name: "GridSummon", + foreign_key: 'party_id', + class_name: 'GridSummon', dependent: :destroy has_many :favorites @@ -50,23 +52,23 @@ class Party < ApplicationRecord user.favorite_parties.include? self end + def blueprint + PartyBlueprint + end + private def skills_are_unique skills = [skill0, skill1, skill2, skill3].compact - if skills.uniq.length != skills.length - errors.add(:skill1, "must be unique") if skill0 == skill1 + return unless skills.uniq.length != skills.length - if skill0 == skill2 || skill1 == skill2 - errors.add(:skill2, "must be unique") - end + errors.add(:skill1, 'must be unique') if skill0 == skill1 - if skill0 == skill3 || skill1 == skill3 || skill2 == skill3 - errors.add(:skill3, "must be unique") - end + errors.add(:skill2, 'must be unique') if skill0 == skill2 || skill1 == skill2 - errors.add(:job_skills, "must be unique") - end + errors.add(:skill3, 'must be unique') if skill0 == skill3 || skill1 == skill3 || skill2 == skill3 + + errors.add(:job_skills, 'must be unique') end end diff --git a/app/models/raid.rb b/app/models/raid.rb index c1065ee..9163f71 100644 --- a/app/models/raid.rb +++ b/app/models/raid.rb @@ -1,2 +1,7 @@ +# frozen_string_literal: true + class Raid < ApplicationRecord + def blueprint + RaidBlueprint + end end diff --git a/app/models/summon.rb b/app/models/summon.rb index bec63b6..7efab1b 100644 --- a/app/models/summon.rb +++ b/app/models/summon.rb @@ -1,24 +1,30 @@ +# frozen_string_literal: true + class Summon < ApplicationRecord - include PgSearch::Model + include PgSearch::Model - pg_search_scope :en_search, - against: :name_en, - using: { - trigram: { - threshold: 0.18 - } - } + pg_search_scope :en_search, + against: :name_en, + using: { + trigram: { + threshold: 0.18 + } + } - pg_search_scope :jp_search, - against: :name_jp, - using: { - tsearch: { - prefix: true, - dictionary: "simple" - } - } + pg_search_scope :jp_search, + against: :name_jp, + using: { + tsearch: { + prefix: true, + dictionary: 'simple' + } + } - def display_resource(summon) - summon.name_en - end + def blueprint + SummonBlueprint + end + + def display_resource(summon) + summon.name_en + end end diff --git a/app/models/user.rb b/app/models/user.rb index b54636a..215885e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,43 +1,49 @@ +# frozen_string_literal: true + class User < ApplicationRecord - before_save { self.email = email.downcase } + before_save { self.email = email.downcase } - ##### ActiveRecord Associations - has_many :parties, dependent: :destroy - has_many :favorites, dependent: :destroy + ##### ActiveRecord Associations + has_many :parties, dependent: :destroy + has_many :favorites, dependent: :destroy - ##### ActiveRecord Validations - validates :username, - presence: true, - length: { minimum: 3, maximum: 26 } + ##### ActiveRecord Validations + validates :username, + presence: true, + length: { minimum: 3, maximum: 26 } - validates :email, - presence: true, - uniqueness: true, - email: true - - validates :password, - length: { minimum: 8 }, - presence: true, - on: :create + validates :email, + presence: true, + uniqueness: true, + email: true - validates :password, - length: { minimum: 8 }, - on: :update, - if: :password_digest_changed? + validates :password, + length: { minimum: 8 }, + presence: true, + on: :create - validates :password_confirmation, - presence: true, - on: :create + validates :password, + length: { minimum: 8 }, + on: :update, + if: :password_digest_changed? - validates :password_confirmation, - presence: true, - on: :update, - if: :password_digest_changed? + validates :password_confirmation, + presence: true, + on: :create -##### ActiveModel Security - has_secure_password + validates :password_confirmation, + presence: true, + on: :update, + if: :password_digest_changed? - def favorite_parties - self.favorites.map { |favorite| favorite.party } - end + ##### ActiveModel Security + has_secure_password + + def favorite_parties + favorites.map(&:party) + end + + def blueprint + UserBlueprint + end end diff --git a/app/models/weapon.rb b/app/models/weapon.rb index 6662330..ed45010 100644 --- a/app/models/weapon.rb +++ b/app/models/weapon.rb @@ -1,24 +1,30 @@ +# frozen_string_literal: true + class Weapon < ApplicationRecord - include PgSearch::Model + include PgSearch::Model - pg_search_scope :en_search, - against: :name_en, - using: { - trigram: { - threshold: 0.18 - } - } + pg_search_scope :en_search, + against: :name_en, + using: { + trigram: { + threshold: 0.18 + } + } - pg_search_scope :jp_search, - against: :name_jp, - using: { - tsearch: { - prefix: true, - dictionary: "simple" - } - } + pg_search_scope :jp_search, + against: :name_jp, + using: { + tsearch: { + prefix: true, + dictionary: 'simple' + } + } - def display_resource(weapon) - weapon.name_en - end + def blueprint + WeaponBlueprint + end + + def display_resource(weapon) + weapon.name_en + end end diff --git a/app/models/weapon_key.rb b/app/models/weapon_key.rb index ac981cb..cfce439 100644 --- a/app/models/weapon_key.rb +++ b/app/models/weapon_key.rb @@ -1,2 +1,7 @@ +# frozen_string_literal: true + class WeaponKey < ApplicationRecord + def blueprint + WeaponKeyBlueprint + end end diff --git a/app/views/api/v1/api/errors.json.rabl b/app/views/api/v1/api/errors.json.rabl deleted file mode 100644 index 78c87ff..0000000 --- a/app/views/api/v1/api/errors.json.rabl +++ /dev/null @@ -1,18 +0,0 @@ -object false - -node :errors do - if @exception.respond_to?(:record) - errors = ValidationErrorsSerializer.new(@exception.record).serialize - end - - if @exception.respond_to?(:message) && @exception.respond_to?(:code) - errors = [ - { - message: @exception.message, - code: @exception.code - } - ] - end - - errors -end diff --git a/app/views/api/v1/api/not_found.json.rabl b/app/views/api/v1/api/not_found.json.rabl deleted file mode 100644 index 9bc7b58..0000000 --- a/app/views/api/v1/api/not_found.json.rabl +++ /dev/null @@ -1,8 +0,0 @@ -object false - -node(:errors) do - { - 'message': "Record could not be found.", - 'code': 'not_found' - } -end \ No newline at end of file diff --git a/app/views/api/v1/characters/base.json.rabl b/app/views/api/v1/characters/base.json.rabl deleted file mode 100644 index 47976a3..0000000 --- a/app/views/api/v1/characters/base.json.rabl +++ /dev/null @@ -1,68 +0,0 @@ -object :character - -attributes :id, - :granblue_id, - :character_id, - :rarity, - :element, - :gender, - :max_level, - :special - -node :name do |w| - { - :en => w.name_en, - :ja => w.name_jp - } -end - -node :uncap do |w| - { - :flb => w.flb, - :ulb => w.ulb - } -end - -node :hp do |w| - { - :min_hp => w.min_hp, - :max_hp => w.max_hp, - :max_hp_flb => w.max_hp_flb - } -end - -node :atk do |w| - { - :min_atk => w.min_atk, - :max_atk => w.max_atk, - :max_atk_flb => w.max_atk_flb - } -end - -node :race do |w| - [ - w.race1, - w.race2 - ] -end - -node :proficiency do |w| - [ - w.proficiency1, - w.proficiency2 - ] -end - -node :data do |w| - { - :base_da => w.base_da, - :base_ta => w.base_ta, - } -end - -node :ougi_ratio do |w| - { - :ougi_ratio => w.ougi_ratio, - :ougi_ratio_flb => w.ougi_ratio_flb - } -end diff --git a/app/views/api/v1/favorites/base.json.rabl b/app/views/api/v1/favorites/base.json.rabl deleted file mode 100644 index e7525b8..0000000 --- a/app/views/api/v1/favorites/base.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object :favorite - -attributes :id, :user_id, :party_id, :created_at, :updated_at diff --git a/app/views/api/v1/favorites/destroyed.json.rabl b/app/views/api/v1/favorites/destroyed.json.rabl deleted file mode 100644 index f791b2f..0000000 --- a/app/views/api/v1/favorites/destroyed.json.rabl +++ /dev/null @@ -1,5 +0,0 @@ -object false - -node :destroyed do - true -end \ No newline at end of file diff --git a/app/views/api/v1/favorites/show.json.rabl b/app/views/api/v1/favorites/show.json.rabl deleted file mode 100644 index 2b85585..0000000 --- a/app/views/api/v1/favorites/show.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @favorite - -extends 'api/v1/favorites/base' \ No newline at end of file diff --git a/app/views/api/v1/grid_characters/base.json.rabl b/app/views/api/v1/grid_characters/base.json.rabl deleted file mode 100644 index 11ca3d7..0000000 --- a/app/views/api/v1/grid_characters/base.json.rabl +++ /dev/null @@ -1,16 +0,0 @@ -attributes :id, - :party_id, - :position, - :uncap_level, - :perpetuity, - -node :object do |c| - partial("characters/base", :object => c.character) -end - -node :awakening do |c| - { - :type => c.awakening_type, - :level => c.awakening_level - } -end diff --git a/app/views/api/v1/grid_characters/conflict.json.rabl b/app/views/api/v1/grid_characters/conflict.json.rabl deleted file mode 100644 index e67e0fc..0000000 --- a/app/views/api/v1/grid_characters/conflict.json.rabl +++ /dev/null @@ -1,14 +0,0 @@ -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 diff --git a/app/views/api/v1/grid_characters/show.json.rabl b/app/views/api/v1/grid_characters/show.json.rabl deleted file mode 100644 index ca858d8..0000000 --- a/app/views/api/v1/grid_characters/show.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @character - -extends 'api/v1/grid_characters/base' \ No newline at end of file diff --git a/app/views/api/v1/grid_summons/base.json.rabl b/app/views/api/v1/grid_summons/base.json.rabl deleted file mode 100644 index 8a20ce9..0000000 --- a/app/views/api/v1/grid_summons/base.json.rabl +++ /dev/null @@ -1,10 +0,0 @@ -attributes :id, - :party_id, - :main, - :friend, - :position, - :uncap_level - -node :object do |s| - partial('summons/base', :object => s.summon) -end \ No newline at end of file diff --git a/app/views/api/v1/grid_summons/show.json.rabl b/app/views/api/v1/grid_summons/show.json.rabl deleted file mode 100644 index 07c4dcb..0000000 --- a/app/views/api/v1/grid_summons/show.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @summon - -extends 'api/v1/grid_summons/base' \ No newline at end of file diff --git a/app/views/api/v1/grid_weapons/base.json.rabl b/app/views/api/v1/grid_weapons/base.json.rabl deleted file mode 100644 index c1d195e..0000000 --- a/app/views/api/v1/grid_weapons/base.json.rabl +++ /dev/null @@ -1,34 +0,0 @@ -attributes :id, - :party_id, - :mainhand, - :position, - :uncap_level, - :element - -node :object do |w| - partial("weapons/base", :object => w.weapon) -end - -node :weapon_keys, :if => lambda { |w| [2, 3, 17, 22].include?(w.weapon.series) } do |w| - partial("weapon_keys/base", :object => w.weapon_keys) -end - -node :ax, :if => lambda { |w| w.weapon.ax > 0 } do |w| - [ - { - :modifier => w.ax_modifier1, - :strength => w.ax_strength1 - }, - { - :modifier => w.ax_modifier2, - :strength => w.ax_strength2 - } - ] -end - -node :awakening, :if => lambda { |w| w.weapon.awakening } do |w| - { - :type => w.awakening_type, - :level => w.awakening_level - } -end diff --git a/app/views/api/v1/grid_weapons/show.json.rabl b/app/views/api/v1/grid_weapons/show.json.rabl deleted file mode 100644 index cd450b3..0000000 --- a/app/views/api/v1/grid_weapons/show.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @weapon - -extends 'api/v1/grid_weapons/base' \ No newline at end of file diff --git a/app/views/api/v1/grid_weapons/update.json.rabl b/app/views/api/v1/grid_weapons/update.json.rabl deleted file mode 100644 index cd450b3..0000000 --- a/app/views/api/v1/grid_weapons/update.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @weapon - -extends 'api/v1/grid_weapons/base' \ No newline at end of file diff --git a/app/views/api/v1/job_skills/all.json.rabl b/app/views/api/v1/job_skills/all.json.rabl deleted file mode 100644 index ba30a1c..0000000 --- a/app/views/api/v1/job_skills/all.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @skills, object_root: false - -extends 'job_skills/base' diff --git a/app/views/api/v1/job_skills/base.json.rabl b/app/views/api/v1/job_skills/base.json.rabl deleted file mode 100644 index 03c6f1e..0000000 --- a/app/views/api/v1/job_skills/base.json.rabl +++ /dev/null @@ -1,10 +0,0 @@ -object :job_skill - -attributes :id, :job, :slug, :color, :main, :base, :sub, :emp, :order - -node :name do |w| - { - :en => w.name_en, - :ja => w.name_jp - } -end diff --git a/app/views/api/v1/jobs/all.json.rabl b/app/views/api/v1/jobs/all.json.rabl deleted file mode 100644 index f39bf78..0000000 --- a/app/views/api/v1/jobs/all.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @jobs, object_root: false - -extends 'jobs/base' diff --git a/app/views/api/v1/jobs/base.json.rabl b/app/views/api/v1/jobs/base.json.rabl deleted file mode 100644 index c806683..0000000 --- a/app/views/api/v1/jobs/base.json.rabl +++ /dev/null @@ -1,17 +0,0 @@ -object :job - -attributes :id, :row, :ml, :order - -node :name do |j| - { - :en => j.name_en, - :ja => j.name_jp - } -end - -node :proficiency do |j| - [ - j.proficiency1, - j.proficiency2 - ] -end \ No newline at end of file diff --git a/app/views/api/v1/jobs/update.json.rabl b/app/views/api/v1/jobs/update.json.rabl deleted file mode 100644 index 6cb851f..0000000 --- a/app/views/api/v1/jobs/update.json.rabl +++ /dev/null @@ -1,20 +0,0 @@ -object @party - -attributes :id, :user_id, :shortcode - -node :is_extra do |p| - p.extra -end - -node :job do |p| - partial("jobs/base", object: p.job) -end - -node :job_skills do |p| - { - "0" => partial("job_skills/base", object: p.skill0), - "1" => partial("job_skills/base", object: p.skill1), - "2" => partial("job_skills/base", object: p.skill2), - "3" => partial("job_skills/base", object: p.skill3), - } -end diff --git a/app/views/api/v1/parties/all.json.rabl b/app/views/api/v1/parties/all.json.rabl deleted file mode 100644 index 44d8477..0000000 --- a/app/views/api/v1/parties/all.json.rabl +++ /dev/null @@ -1,11 +0,0 @@ -node :count do - @count -end - -node :total_pages do - (@count.to_f / @per_page > 1) ? (@count.to_f / @per_page).ceil() : 1 -end - -node(:results) { - partial('parties/base', object: @parties) -} unless @parties.empty? diff --git a/app/views/api/v1/parties/base.json.rabl b/app/views/api/v1/parties/base.json.rabl deleted file mode 100644 index 364c711..0000000 --- a/app/views/api/v1/parties/base.json.rabl +++ /dev/null @@ -1,47 +0,0 @@ -object :party - -attributes :id, - :name, - :description, - :element, - :favorited, - :shortcode, - :created_at, - :updated_at - -node :extra do |p| - p.extra -end - -node :user do |p| - partial("users/base", object: p.user) -end - -node :raid do |p| - partial("raids/base", object: p.raid) -end - -node :job do |p| - partial("jobs/base", object: p.job) -end - -node :job_skills do |p| - { - "0" => partial("job_skills/base", object: p.skill0), - "1" => partial("job_skills/base", object: p.skill1), - "2" => partial("job_skills/base", object: p.skill2), - "3" => partial("job_skills/base", object: p.skill3), - } -end - -node :characters do |p| - partial("grid_characters/base", object: p.characters) -end - -node :weapons do |p| - partial("grid_weapons/base", object: p.weapons) -end - -node :summons do |p| - partial("grid_summons/base", object: p.summons) -end diff --git a/app/views/api/v1/parties/characters.json.rabl b/app/views/api/v1/parties/characters.json.rabl deleted file mode 100644 index e19cb56..0000000 --- a/app/views/api/v1/parties/characters.json.rabl +++ /dev/null @@ -1,15 +0,0 @@ -object @party - -attributes :id, :name, :description, :shortcode, :favorited, :created_at, :updated_at - -node :user do |p| - partial('users/base', :object => p.user) -end - -node :raid do |p| - partial('raids/base', :object => p.raid) -end - -node :characters do |p| - partial('grid_characters/base', :object => p.characters) -end diff --git a/app/views/api/v1/parties/destroyed.json.rabl b/app/views/api/v1/parties/destroyed.json.rabl deleted file mode 100644 index f791b2f..0000000 --- a/app/views/api/v1/parties/destroyed.json.rabl +++ /dev/null @@ -1,5 +0,0 @@ -object false - -node :destroyed do - true -end \ No newline at end of file diff --git a/app/views/api/v1/parties/show.json.rabl b/app/views/api/v1/parties/show.json.rabl deleted file mode 100644 index 88809bc..0000000 --- a/app/views/api/v1/parties/show.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @party - -extends 'api/v1/parties/base' \ No newline at end of file diff --git a/app/views/api/v1/parties/summons.json.rabl b/app/views/api/v1/parties/summons.json.rabl deleted file mode 100644 index d823f06..0000000 --- a/app/views/api/v1/parties/summons.json.rabl +++ /dev/null @@ -1,15 +0,0 @@ -object @party - -attributes :id, :name, :description, :shortcode, :favorited, :created_at, :updated_at - -node :user do |p| - partial('users/base', :object => p.user) -end - -node :raid do |p| - partial('raids/base', :object => p.raid) -end - -node :summons do |p| - partial('grid_summons/base', :object => p.summons) -end diff --git a/app/views/api/v1/parties/update.json.rabl b/app/views/api/v1/parties/update.json.rabl deleted file mode 100644 index 6cb851f..0000000 --- a/app/views/api/v1/parties/update.json.rabl +++ /dev/null @@ -1,20 +0,0 @@ -object @party - -attributes :id, :user_id, :shortcode - -node :is_extra do |p| - p.extra -end - -node :job do |p| - partial("jobs/base", object: p.job) -end - -node :job_skills do |p| - { - "0" => partial("job_skills/base", object: p.skill0), - "1" => partial("job_skills/base", object: p.skill1), - "2" => partial("job_skills/base", object: p.skill2), - "3" => partial("job_skills/base", object: p.skill3), - } -end diff --git a/app/views/api/v1/parties/weapons.json.rabl b/app/views/api/v1/parties/weapons.json.rabl deleted file mode 100644 index 3722385..0000000 --- a/app/views/api/v1/parties/weapons.json.rabl +++ /dev/null @@ -1,19 +0,0 @@ -object @party - -attributes :id, :name, :description, :shortcode, :favorited, :created_at, :updated_at - -node :user do |p| - partial('users/base', :object => p.user) -end - -node :raid do |p| - partial('raids/base', :object => p.raid) -end - -node :extra do |p| - p.extra -end - -node :weapons do |p| - partial('grid_weapons/base', :object => p.weapons) -end diff --git a/app/views/api/v1/raids/all.json.rabl b/app/views/api/v1/raids/all.json.rabl deleted file mode 100644 index b6abde3..0000000 --- a/app/views/api/v1/raids/all.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @raids - -extends 'raids/base' diff --git a/app/views/api/v1/raids/base.json.rabl b/app/views/api/v1/raids/base.json.rabl deleted file mode 100644 index 362a5df..0000000 --- a/app/views/api/v1/raids/base.json.rabl +++ /dev/null @@ -1,10 +0,0 @@ -object :raid - -attributes :id, :slug, :level, :group, :element - -node :name do |r| - { - :en => r.name_en, - :ja => r.name_jp - } -end \ No newline at end of file diff --git a/app/views/api/v1/search/characters.json.rabl b/app/views/api/v1/search/characters.json.rabl deleted file mode 100644 index ab551fa..0000000 --- a/app/views/api/v1/search/characters.json.rabl +++ /dev/null @@ -1,11 +0,0 @@ -node :count do - @count -end - -node :total_pages do - (@count.to_f / 10 > 1) ? (@count.to_f / 10).ceil() : 1 -end - -node(:results) { - partial('characters/base', object: @characters) -} unless @characters.empty? diff --git a/app/views/api/v1/search/job_skills.json.rabl b/app/views/api/v1/search/job_skills.json.rabl deleted file mode 100644 index 100cca8..0000000 --- a/app/views/api/v1/search/job_skills.json.rabl +++ /dev/null @@ -1,11 +0,0 @@ -node :count do - @count -end - -node :total_pages do - (@count.to_f / 10 > 1) ? (@count.to_f / 10).ceil() : 1 -end - -node(:results) { - partial('job_skills/base', object: @skills) -} unless @skills.empty? diff --git a/app/views/api/v1/search/summons.json.rabl b/app/views/api/v1/search/summons.json.rabl deleted file mode 100644 index 073eb1e..0000000 --- a/app/views/api/v1/search/summons.json.rabl +++ /dev/null @@ -1,11 +0,0 @@ -node :count do - @count -end - -node :total_pages do - (@count.to_f / 10 > 1) ? (@count.to_f / 10).ceil() : 1 -end - -node(:results) { - partial('summons/base', object: @summons) -} unless @summons.empty? diff --git a/app/views/api/v1/search/weapons.json.rabl b/app/views/api/v1/search/weapons.json.rabl deleted file mode 100644 index b759323..0000000 --- a/app/views/api/v1/search/weapons.json.rabl +++ /dev/null @@ -1,11 +0,0 @@ -node :count do - @count -end - -node :total_pages do - (@count.to_f / 10 > 1) ? (@count.to_f / 10).ceil() : 1 -end - -node(:results) { - partial('weapons/base', object: @weapons) -} unless @weapons.empty? diff --git a/app/views/api/v1/summons/base.json.rabl b/app/views/api/v1/summons/base.json.rabl deleted file mode 100644 index 3811753..0000000 --- a/app/views/api/v1/summons/base.json.rabl +++ /dev/null @@ -1,39 +0,0 @@ -object :summon - -attributes :id, - :granblue_id, - :element, - :rarity, - :max_level - -node :name do |w| - { - :en => w.name_en, - :ja => w.name_jp - } -end - -node :uncap do |w| - { - :flb => w.flb, - :ulb => w.ulb - } -end - -node :hp do |w| - { - :min_hp => w.min_hp, - :max_hp => w.max_hp, - :max_hp_flb => w.max_hp_flb, - :max_hp_ulb => w.max_hp_ulb - } -end - -node :atk do |w| - { - :min_atk => w.min_atk, - :max_atk => w.max_atk, - :max_atk_flb => w.max_atk_flb, - :max_atk_ulb => w.max_atk_ulb - } -end \ No newline at end of file diff --git a/app/views/api/v1/users/available.json.rabl b/app/views/api/v1/users/available.json.rabl deleted file mode 100644 index 4efcddb..0000000 --- a/app/views/api/v1/users/available.json.rabl +++ /dev/null @@ -1,5 +0,0 @@ -object false - -node(:available) { - @available -} \ No newline at end of file diff --git a/app/views/api/v1/users/base.json.rabl b/app/views/api/v1/users/base.json.rabl deleted file mode 100644 index 642c3f8..0000000 --- a/app/views/api/v1/users/base.json.rabl +++ /dev/null @@ -1,15 +0,0 @@ -object :user - -attributes :id, - :username, - :granblue_id, - :language, - :private, - :gender - -node :picture do |u| - { - :picture => u.picture, - :element => u.element - } -end \ No newline at end of file diff --git a/app/views/api/v1/users/create.json.rabl b/app/views/api/v1/users/create.json.rabl deleted file mode 100644 index cea7c27..0000000 --- a/app/views/api/v1/users/create.json.rabl +++ /dev/null @@ -1,9 +0,0 @@ -object false - -node(:user) { - @presenter -} unless @user.blank? - -node(:error) { - @error -} unless @error.blank? diff --git a/app/views/api/v1/users/info.json.rabl b/app/views/api/v1/users/info.json.rabl deleted file mode 100644 index b10685a..0000000 --- a/app/views/api/v1/users/info.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -object @user - -extends 'api/v1/users/base' \ No newline at end of file diff --git a/app/views/api/v1/users/show.json.rabl b/app/views/api/v1/users/show.json.rabl deleted file mode 100644 index 9a729da..0000000 --- a/app/views/api/v1/users/show.json.rabl +++ /dev/null @@ -1,19 +0,0 @@ -object false - -node :user do - partial('users/base', object: @user) -end - -child :parties do - node :count do - @count - end - - node :total_pages do - (@count.to_f / @per_page > 1) ? (@count.to_f / @per_page).ceil() : 1 - end - - node :results do - partial('parties/base', object: @parties) - end unless @parties.empty? -end \ No newline at end of file diff --git a/app/views/api/v1/weapon_keys/all.json.rabl b/app/views/api/v1/weapon_keys/all.json.rabl deleted file mode 100644 index f631ea6..0000000 --- a/app/views/api/v1/weapon_keys/all.json.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @keys - -extends 'weapon_keys/base' diff --git a/app/views/api/v1/weapon_keys/base.json.rabl b/app/views/api/v1/weapon_keys/base.json.rabl deleted file mode 100644 index 033be8e..0000000 --- a/app/views/api/v1/weapon_keys/base.json.rabl +++ /dev/null @@ -1,10 +0,0 @@ -object :weapon_key - -attributes :id, :series, :slot, :group, :order - -node :name do |k| - { - :en => k.name_en, - :ja => k.name_jp - } -end \ No newline at end of file diff --git a/app/views/api/v1/weapons/base.json.rabl b/app/views/api/v1/weapons/base.json.rabl deleted file mode 100644 index 1b464e5..0000000 --- a/app/views/api/v1/weapons/base.json.rabl +++ /dev/null @@ -1,45 +0,0 @@ -object :weapon - -attributes :id, - :granblue_id, - :element, - :proficiency, - :max_level, - :max_skill_level, - :limit, - :rarity, - :series, - :ax, - :awakening - -node :name do |w| - { - :en => w.name_en, - :ja => w.name_jp - } -end - -node :uncap do |w| - { - :flb => w.flb, - :ulb => w.ulb - } -end - -node :hp do |w| - { - :min_hp => w.min_hp, - :max_hp => w.max_hp, - :max_hp_flb => w.max_hp_flb, - :max_hp_ulb => w.max_hp_ulb - } -end - -node :atk do |w| - { - :min_atk => w.min_atk, - :max_atk => w.max_atk, - :max_atk_flb => w.max_atk_flb, - :max_atk_ulb => w.max_atk_ulb - } -end diff --git a/config/environments/development.rb b/config/environments/development.rb index 143f8d4..6e13811 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,9 @@ Rails.application.configure do + config.after_initialize do + ActiveRecord::Base.logger = Rails.logger.clone + ActiveRecord::Base.logger.level = Logger::INFO + end + # Settings specified here will take precedence over those in config/application.rb. config.hosts << "grid-api.ngrok.io" diff --git a/config/initializers/blueprinter.rb b/config/initializers/blueprinter.rb new file mode 100644 index 0000000..2b4eb99 --- /dev/null +++ b/config/initializers/blueprinter.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'oj' # you can skip this if OJ has already been required. + +Blueprinter.configure do |config| + config.generator = Oj # default is JSON + config.sort_fields_by = :definition +end diff --git a/config/initializers/rabl.rb b/config/initializers/rabl.rb deleted file mode 100644 index 8bdb4fe..0000000 --- a/config/initializers/rabl.rb +++ /dev/null @@ -1,3 +0,0 @@ -Rabl.configure do |config| - config.view_paths = [Rails.root.join('app', 'views', 'api', 'v1')] -end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index f7f94e2..de3e5f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,13 +1,13 @@ Rails.application.routes.draw do use_doorkeeper do - controllers :tokens => 'tokens' + controllers tokens: 'tokens' skip_controllers :applications, :authorized_applications end namespace :api, defaults: { format: :json } do namespace :v1 do - resources :parties, only: [:index, :create, :update, :destroy] - resources :users, only: [:create, :update, :show] + resources :parties, only: %i[index create update destroy] + resources :users, only: %i[create update show] resources :grid_weapons, only: [:update] resources :favorites, only: [:create] @@ -15,9 +15,6 @@ Rails.application.routes.draw do get 'parties/favorites', to: 'parties#favorites' get 'parties/:id', to: 'parties#show' - get 'parties/:id/weapons', to: 'parties#weapons' - get 'parties/:id/summons', to: 'parties#summons' - get 'parties/:id/characters', to: 'parties#characters' put 'parties/:id/jobs', to: 'jobs#update_job' put 'parties/:id/job_skills', to: 'jobs#update_job_skills' diff --git a/spec/requests/job_skills_spec.rb b/spec/requests/job_skills_spec.rb new file mode 100644 index 0000000..baadd9d --- /dev/null +++ b/spec/requests/job_skills_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "JobSkills", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end