vol1ura/Sat_9am_5km

View on GitHub
app/models/activity.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

class Activity < ApplicationRecord
  audited
  has_associated_audits

  MAX_SCANNERS = 5

  belongs_to :event

  has_many :results, dependent: :destroy
  has_many :athletes, through: :results
  has_many :volunteers, dependent: :destroy, inverse_of: :activity

  validates :date, presence: true
  validates_associated :volunteers, if: :will_save_change_to_date?

  after_commit :postprocessing, if: :saved_change_to_published?

  scope :published, -> { where(published: true) }
  scope :in_country, ->(country_code) { joins(event: :country).where(country: { code: country_code }) }

  delegate :name, to: :event, prefix: true

  def self.ransackable_attributes(_auth_object = nil)
    %w[date event_id]
  end

  def volunteers_roster
    volunteers
      .joins("LEFT JOIN volunteering_positions vp ON vp.event_id = #{event_id} AND vp.role = volunteers.role")
      .order(:rank)
  end

  def participants
    Athlete.where(id: results.select(:athlete_id)).or(Athlete.where(id: volunteers.select(:athlete_id))).distinct
  end

  def leader_result(male: true)
    results.joins(:athlete).where(athlete: { male: }).order(:position).first
  end

  def number
    event.activities.published.where(date: ...date).size.next
  end

  def correct?
    subquery = results.left_joins(:athlete).select(
      'position, LEAD(position, 1) OVER (ORDER BY position) AS next_position, ' \
      'total_time, LEAD(total_time, 1) OVER (ORDER BY position) AS next_total_time, ' \
      'athlete_id, name, male',
    ).to_sql
    Result
      .from("(#{subquery}) AS ext_results")
      .where(
        'total_time IS NULL OR next_position != position + 1 OR total_time > next_total_time OR ' \
        '(athlete_id IS NOT NULL AND (name IS NULL OR male IS NULL))',
      )
      .empty?
  end

  def postprocessing
    return unless published

    ResultsProcessingJob.perform_later(id)
    AthletesAwardingJob.perform_later(id)
    BreakingTimeAwardingJob.perform_later(id)
    FivePlusAwardingJob.perform_later(id)
    AthleteStatsUpdateJob.set(wait: 10.minutes).perform_later(participants.ids)
    Telegram::Notification::AfterActivityJob.perform_later(id)
    ClearCache.call
  end
end