Skip to content

Commit

Permalink
Merge pull request #196 from plural/advanced-deck-validation
Browse files Browse the repository at this point in the history
Advanced deck validation
  • Loading branch information
plural authored Sep 1, 2023
2 parents bd1b174 + 65d2a95 commit 0b12874
Show file tree
Hide file tree
Showing 20 changed files with 1,827 additions and 111 deletions.
66 changes: 38 additions & 28 deletions app/controllers/api/v3/public/validate_deck_controller.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
module API
module V3
module Public
class Api::V3::Public::ValidateDeckController < ::ApplicationController
def index
out = params[:data]
module V3
module Public
class Api::V3::Public::ValidateDeckController < ::ApplicationController
def index
out = params[:data]

# Check for presence of everything needed to perform deck validation and error if not present.
if out.nil? or not (out.has_key?(:attributes) and out[:attributes].has_key?(:identity_card_id) and out[:attributes].has_key?(:side_id) and out[:attributes].has_key?(:cards))
return render json: {
:errors => [{
:title => "Invalid request",
:detail => "Valid requests must be of the form `{'data': { 'attributes': { 'identity_card_id': 'foo', 'side_id': 'bar', 'cards': { } } }
}`. Extra fields are allowed.",
:code => "400",
:status => "400"
}]}, :status => :bad_request
end
# Check for presence of everything needed to perform deck validation and error if not present.
if out.nil? or not (
out.has_key?(:attributes) and
out[:attributes].has_key?(:identity_card_id) and
out[:attributes].has_key?(:side_id) and
out[:attributes].has_key?(:cards) and
out[:attributes].has_key?(:validations))
return render json: {
:errors => [{
:title => "Invalid request",
:detail => "Valid requests must be of the form `{'data': { 'attributes': { 'identity_card_id': 'foo', 'side_id': 'bar', 'cards': { }, 'validations': [] } }}`. Extra fields are allowed.",
:code => "400",
:status => "400"
}]}, :status => :bad_request
end

# Deck validation takes in a simple datastructure, so construct it instead of passing around ActionController::Parameters
deck = {
'identity_card_id' => params[:data][:attributes][:identity_card_id],
'side_id' => params[:data][:attributes][:side_id],
'cards' => {},
'validations' => [],
}
params[:data][:attributes][:cards].each {|c,q| deck['cards'][c] = q}
params[:data][:attributes][:validations].each do |v|
deck['validations'] << v
end

# Deck validation works off of a simple datastructure, so construct it instead of passing around ActionController::Parameters
deck = {
'identity_card_id' => params[:data][:attributes][:identity_card_id],
'side_id' => params[:data][:attributes][:side_id],
'cards' => {}
}
params[:data][:attributes][:cards].each {|c,q| deck['cards'][c] = q}
v = DeckValidator.new(deck)

v = DeckValidator.new(deck)
out[:attributes][:is_valid] = v.is_valid?
out[:attributes][:validation_errors] = v.errors
out[:attributes][:validations] = v.validations

out[:attributes][:is_valid] = v.is_valid?
out[:attributes][:validation_errors] = v.errors
render json: { data: out }, :status => :ok
end
render json: { data: out }, :status => :ok
end
end
end
end
end
2 changes: 2 additions & 0 deletions app/models/format.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ class Format < ApplicationRecord
has_many :card_pools, :through => :snapshots
has_many :restrictions, :through => :snapshots

has_one :snapshot, primary_key: :active_snapshot_id, foreign_key: :id

validates :name, uniqueness: true
end
4 changes: 4 additions & 0 deletions app/models/unified_restriction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ def readonly?
belongs_to :card_pool
belongs_to :restriction
belongs_to :card

scope :cards_restricted_by, ->(restriction_id) { where(
'restriction_id = ? AND (in_restriction OR is_banned OR is_restricted OR eternal_points > 0 ' +
'OR has_global_penalty OR universal_faction_cost > 0)', restriction_id) }
end
4 changes: 4 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
# data for all the tests and the API doc generation.
if Rails.env == 'test'
Rake::Task["db:fixtures:load"].invoke

Scenic.database.refresh_materialized_view(:unified_restrictions, concurrently: false, cascade: false)
Scenic.database.refresh_materialized_view(:unified_cards, concurrently: false, cascade: false)
Scenic.database.refresh_materialized_view(:unified_printings, concurrently: false, cascade: false)
end
92 changes: 92 additions & 0 deletions lib/deck_validation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# A class to hold specifications and results from validations.
class DeckValidation
attr_reader :basic_deckbuilding_rules
attr_reader :label
attr_reader :errors
attr_reader :format_id
attr_reader :restriction_id
attr_reader :card_pool_id
attr_reader :snapshot_id

def initialize(validation_hash)
@label = nil
if validation_hash.has_key?('label')
@label = validation_hash['label']
end
@basic_deckbuilding_rules = false
if validation_hash.has_key?('basic_deckbuilding_rules')
@basic_deckbuilding_rules = validation_hash['basic_deckbuilding_rules']
end
@format_id = nil
if validation_hash.has_key?('format_id')
@format_id = validation_hash['format_id']
end
@restriction_id = nil
if validation_hash.has_key?('restriction_id')
@restriction_id = validation_hash['restriction_id']
end
@card_pool_id = nil
if validation_hash.has_key?('card_pool_id')
@card_pool_id = validation_hash['card_pool_id']
end
@snapshot_id = nil
if validation_hash.has_key?('snapshot_id')
@snapshot_id = validation_hash['snapshot_id']
end

expand_implied_ids

@errors = []
end

def expand_implied_ids
if !@snapshot_id.nil? and (@format_id.nil? or @card_pool_id.nil? or @restriction_id.nil?)
if Snapshot.exists?(@snapshot_id)
snapshot = Snapshot.find(@snapshot_id)
if @format_id.nil?
@format_id = snapshot.format_id
end
if @card_pool_id.nil?
@card_pool_id = snapshot.card_pool_id
end
if @restriction_id.nil?
@restriction_id = snapshot.restriction_id
end
end
elsif !@format_id.nil? and (@snapshot_id.nil? or @card_pool_id.nil? or @restriction_id.nil?)
if Format.exists?(@format_id)
format = Format.find(@format_id)
if @snapshot_id.nil?
@snapshot_id = format.active_snapshot_id
end
active_snapshot = format.snapshot
if !active_snapshot.nil?
if @card_pool_id.nil?
@card_pool_id = active_snapshot.card_pool_id
end
if @restriction_id.nil?
@restriction_id = active_snapshot.restriction_id
end
end
end
elsif !@card_pool_id.nil? and @format_id.nil?
if CardPool.exists?(@card_pool_id)
card_pool = CardPool.find(@card_pool_id)
@format_id = card_pool.format_id
end
elsif !@restriction_id.nil? and @format_id.nil?
if Restriction.exists?(@restriction_id)
restriction = Restriction.find(@restriction_id)
@format_id = restriction.format_id
end
end
end

def add_error(e)
@errors << e
end

def is_valid?
return @errors.size == 0
end
end
Loading

0 comments on commit 0b12874

Please sign in to comment.