146 lines
3.9 KiB
Ruby
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
|