106 lines
3.1 KiB
Ruby
106 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'securerandom'
|
|
|
|
class Tournament < ApplicationRecord
|
|
belongs_to :user
|
|
has_many :teams, dependent: :destroy
|
|
has_many :stages, dependent: :destroy
|
|
has_many :beamers, dependent: :destroy
|
|
has_many :team_action_lists, dependent: :destroy
|
|
|
|
validates :name, presence: true
|
|
validates :code, presence: true, uniqueness: true
|
|
validates :timer_mode, inclusion: { in: %w[countdown countup] }, allow_nil: true
|
|
validates :sync_target_url, format: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true
|
|
validate :sync_configuration_is_complete
|
|
|
|
validate :playoff_teams_amount_is_positive_power_of_two
|
|
|
|
alias_attribute :owner, :user
|
|
|
|
after_initialize :generate_code
|
|
after_create_commit :ensure_default_beamer!
|
|
before_validation :clear_follower_sync_token_when_disabling_read_only_mode
|
|
after_commit :broadcast_timer_state_change, if: :saved_change_to_timer_state?
|
|
|
|
def matches
|
|
[stages.map(&:matches), stages.map { |s| s.groups.map(&:matches) }].flatten
|
|
end
|
|
|
|
def teams_advancing_from_group_stage
|
|
group_stage = self.group_stage
|
|
return [] if group_stage.nil?
|
|
|
|
GroupStageService.get_advancing_teams(group_stage)
|
|
end
|
|
|
|
def group_stage
|
|
# get the stage with level -1 (group stage)
|
|
stages.find { |stage| stage.level == -1 }
|
|
end
|
|
|
|
def sync_push_enabled?
|
|
sync_target_url.present? && sync_auth_token.present? && !read_only_mode?
|
|
end
|
|
|
|
def sync_accepts_push?
|
|
read_only_mode? && sync_auth_token.present?
|
|
end
|
|
|
|
private
|
|
|
|
def generate_code
|
|
return unless code.nil?
|
|
|
|
loop do
|
|
self.code = SecureRandom.hex(3)
|
|
break if errors['code'].blank?
|
|
end
|
|
end
|
|
|
|
def playoff_teams_amount_is_positive_power_of_two
|
|
return if (Utils.po2?(playoff_teams_amount) && playoff_teams_amount.positive?) || playoff_teams_amount.zero?
|
|
|
|
errors.add(:playoff_teams_amount,
|
|
'playoff_teams_amount needs to be a positive power of two')
|
|
end
|
|
|
|
def sync_configuration_is_complete
|
|
return if sync_target_url.blank? && sync_auth_token.blank?
|
|
return if sync_target_url.present? && sync_auth_token.present?
|
|
return if read_only_mode? && sync_auth_token.present? && sync_target_url.blank?
|
|
|
|
errors.add(:base, 'sync_target_url and sync_auth_token must be configured together')
|
|
end
|
|
|
|
def ensure_default_beamer!
|
|
beamers.find_or_create_by!(name: Beamer::DEFAULT_NAME) do |beamer|
|
|
beamer.display_state = 'matches_all'
|
|
end
|
|
end
|
|
|
|
def sync_configuration_is_complete
|
|
return if sync_target_url.blank? && sync_auth_token.blank?
|
|
return if sync_target_url.present? && sync_auth_token.present?
|
|
return if read_only_mode? && sync_auth_token.present? && sync_target_url.blank?
|
|
|
|
errors.add(:base, 'sync_target_url and sync_auth_token must be configured together')
|
|
end
|
|
|
|
def clear_follower_sync_token_when_disabling_read_only_mode
|
|
return if read_only_mode?
|
|
return if sync_target_url.present?
|
|
|
|
self.sync_auth_token = nil
|
|
end
|
|
|
|
def saved_change_to_timer_state?
|
|
saved_change_to_timestamp? || saved_change_to_timer_mode?
|
|
end
|
|
|
|
def broadcast_timer_state_change
|
|
TournamentTimerBroadcast.call(id)
|
|
end
|
|
end
|