Files

146 lines
3.9 KiB
Ruby

class Tournament < ApplicationRecord
include Coverable
FORMAT_KINDS = %w[groups knockout mixed free].freeze
STATUSES = %w[draft published live archived].freeze
INTERNAL_TEAM_KIND = "tournament_broadcast"
belongs_to :club
belongs_to :broadcast_team, class_name: "Team", optional: true
has_many :broadcast_assignments, class_name: "TournamentBroadcastAssignment", dependent: :destroy
has_many :matches, dependent: :destroy
has_many :broadcast_invitations, class_name: "TournamentBroadcastInvitation", dependent: :destroy
has_many :participants, class_name: "TournamentParticipant", dependent: :destroy
has_many :rounds, class_name: "TournamentRound", dependent: :destroy
has_many :groups, class_name: "TournamentGroup", dependent: :destroy
has_many_attached :invite_email_images
has_one_attached :logo_file
validates :name, presence: true
validates :slug, presence: true, uniqueness: true,
format: { with: /\A[a-z0-9]+(?:-[a-z0-9]+)*\z/, message: "solo lettere minuscole, numeri e trattini" }
validates :sport_key, presence: true
validates :starts_on, :ends_on, presence: true
validates :format_kind, inclusion: { in: FORMAT_KINDS }
validates :status, inclusion: { in: STATUSES }
validates :invite_draft_note, length: { maximum: 2000 }, allow_blank: true
validate :sport_key_known
validate :ends_on_not_before_starts_on
validate :logo_file_type, if: -> { logo_file.attached? }
before_validation :normalize_sport_key
before_validation :assign_slug, on: :create
before_validation :normalize_slug, if: -> { slug_changed? && slug.present? }
before_validation :normalize_courts
scope :visible_to_public, -> { where(status: %w[published live archived]) }
scope :listed_on_live, -> { where(status: %w[published live]) }
scope :search_public, lambda { |query|
q = query.to_s.strip
return all if q.blank?
term = "%#{sanitize_sql_like(q)}%"
left_joins(:club).where(
"tournaments.name ILIKE :term OR clubs.name ILIKE :term OR tournaments.venue ILIKE :term",
term: term
)
}
def published?
status.in?(%w[published live archived])
end
def archived?
status == "archived"
end
def writable?
!archived?
end
def uses_groups?
format_kind.in?(%w[groups mixed])
end
def uses_knockout?
format_kind.in?(%w[knockout mixed])
end
def court_list
Array(courts).map { |c| c.to_s.strip }.reject(&:blank?)
end
def days
(starts_on..ends_on).to_a
end
def sport_label
Sports::Catalog.find_optional(sport_key)&.dig(:label) || sport_key.to_s.humanize
end
def public_page_path
Rails.application.routes.url_helpers.public_tournament_page_path(slug)
end
def effective_primary_color
club.effective_primary_color
end
def effective_secondary_color
club.effective_secondary_color
end
def effective_logo_url
return unless logo_file.attached?
Rails.application.routes.url_helpers.rails_blob_path(logo_file, only_path: true)
end
def concurrent_limit
club.subscription&.plan&.concurrent_streams_limit
end
private
def normalize_sport_key
self.sport_key = Sports::Catalog.normalize_key(sport_key) if sport_key.present?
end
def sport_key_known
return if sport_key.blank?
return if Sports::Catalog.find_optional(sport_key)
errors.add(:sport_key, "non valido")
end
def ends_on_not_before_starts_on
return if starts_on.blank? || ends_on.blank?
return if ends_on >= starts_on
errors.add(:ends_on, "non può precedere la data di inizio")
end
def assign_slug
self.slug = Tournaments::GenerateSlug.call(self) if slug.blank?
end
def normalize_slug
self.slug = slug.to_s.parameterize
end
def normalize_courts
self.courts = court_list
self.courts = ["Campo 1"] if courts.blank?
end
def cover_parent
club
end
def logo_file_type
return if logo_file.content_type.in?(Coverable::COVER_IMAGE_TYPES)
errors.add(:logo_file, I18n.t("coverable.errors.invalid_type"))
end
end