Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def visible_events
events.visible
end

# @return [Event::ActiveRecord_AssociationRelation]
def projectable_events
events.used_for_projections
end

# @return [String, nil]
def home_time_zone
events.latest&.home_time_zone
Expand Down
1 change: 1 addition & 0 deletions app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Event < ApplicationRecord
after_touch :notify_event_update, if: :topic_resource_key?

scope :name_search, ->(search_param) { where("events.name ILIKE ?", "%#{search_param}%") }
scope :used_for_projections, -> { where(use_for_projections: true) }
scope :select_with_params, lambda { |search_param|
search(search_param)
.left_joins(:efforts).left_joins(:event_group)
Expand Down
3 changes: 1 addition & 2 deletions app/models/projection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ def self.sql(split_time:, starting_time_point:, subject_time_points:, ignore_tim
relevant_event_ids as (
select events.id as event_id
from events
join event_groups on event_groups.id = events.event_group_id
join courses on courses.id = events.course_id
join splits on splits.course_id = courses.id
where splits.id = #{starting_split_id}
and (event_groups.concealed is false or event_groups.concealed is null)
and events.use_for_projections is true
and (#{ignore_timestamp} is null or events.scheduled_start_time <= #{ignore_timestamp})
order by scheduled_start_time desc
limit #{EVENT_LOOKBACK_COUNT}
Expand Down
1 change: 1 addition & 0 deletions app/parameters/event_parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def self.permitted
:results_template_id,
:notice_text,
:lottery_id,
:use_for_projections,
]
end

Expand Down
12 changes: 10 additions & 2 deletions app/view_models/plan_display.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ class PlanDisplay < EffortWithLapSplitRows

include CourseAnalysisMethods
include TimeFormats

attr_reader :course, :error_messages

delegate :name, :organization, :simple?, to: :course
delegate :multiple_laps?, to: :event, allow_nil: true

def initialize(args)
def initialize(args) # rubocop:disable Lint/MissingSuper
@course = args[:course]
@params = args[:params]
@error_messages = []
validate_setup
end

# Overrides CourseAnalysisMethods#event: planning anchors on the same
# events the projection engine draws data from, so a course whose only
# events are concealed seed events can still plan
def event
@event ||= course.projectable_events.latest
end

def effort
@effort ||= event.efforts.new
end
Expand Down Expand Up @@ -103,7 +111,7 @@ def lap_splits
end

def validate_setup
error_messages << "No events have been held on this course." if course.visible_events.empty?
error_messages << "No events on this course are available for planning." if course.projectable_events.empty?
AssignSegmentTimes.perform(ordered_split_times) if error_messages.empty?
rescue ArgumentError => e
error_messages << e.message
Expand Down
11 changes: 11 additions & 0 deletions app/views/events/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,17 @@
<%= form.text_field :beacon_url, class: "form-control", placeholder: "example.com/tracking/my-event" %>
</div>
</div>

<div class="row">
<div class="mb-3 col">
<%= form.label :use_for_projections, "Use this event's times for projections", class: "me-2" %>
<span tabindex="-1"
data-controller="tooltip"
data-bs-placement="bottom"
data-bs-original-title="When checked, this event's split times help power pacing plans and live projections for events on this course, even if this event is not public. Uncheck if this event's times are unreliable (for example, unrealistic test data or serious timing problems) and should not influence predictions."><i class="fas fa-circle-question"></i></span>
<%= form.check_box :use_for_projections %>
</div>
</div>
</div>

<br>
Expand Down
16 changes: 16 additions & 0 deletions spec/models/projection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,22 @@
end
end

context "when an event on the course is flagged not to be used for projections" do
before { events(:hardrock_2014).update_column(:use_for_projections, false) }

it "does not draw from that event's efforts" do
expect(subject.first.effort_years).to eq([2016])
end
end

context "when an event in a concealed event group is flagged for projections" do
before { event_groups(:hardrock_2014).update_column(:concealed, true) }

it "draws from that event's efforts" do
expect(subject.first.effort_years).to eq([2014, 2016])
end
end

context "when given a starting split time" do
let(:split_time) { effort.ordered_split_times.first }
it "returns an empty array" do
Expand Down
4 changes: 2 additions & 2 deletions spec/system/plan_effort_flow_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@
visit_page

verify_content_present(course)
expect(page).to have_content("No events have been held on this course.")
expect(page).to have_content("No events on this course are available for planning.")
end
end

scenario "Inputmask works", js: true do
scenario "Inputmask works", :js do
visit_page

expected_values = {
Expand Down
32 changes: 32 additions & 0 deletions spec/view_models/plan_display_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require "rails_helper"

RSpec.describe PlanDisplay do
subject { described_class.new(course: course, params: ActionController::Parameters.new(params)) }

let(:course) { courses(:hardrock_ccw) }
let(:params) { { expected_time: "38:00" } }

context "when the course has visible events with relevant data" do
it "returns no errors and builds projected split times" do
expect(subject.error_messages).to be_empty
expect(subject.ordered_split_times).to be_present
end
end

context "when the course's only event is in a concealed event group but flagged for projections" do
before { event_groups(:hardrock_2015).update_column(:concealed, true) }

it "returns no errors and builds projected split times" do
expect(subject.error_messages).to be_empty
expect(subject.ordered_split_times).to be_present
end
end

context "when no events on the course are flagged for projections" do
before { course.events.each { |event| event.update_column(:use_for_projections, false) } }

it "returns an error message" do
expect(subject.error_messages).to include("No events on this course are available for planning.")
end
end
end