Skip to content
Open
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
44 changes: 24 additions & 20 deletions app/models/participant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,49 @@ def self.ransackable_associations(auth_object = nil)
end

def restrict_after(datetime, weight=1, event=Event.current_event)
event.timeslots.each do |timeslot|
if timeslot.ends_at > datetime
self.presenter_timeslot_restrictions.create!(
timeslot: timeslot,
weight: weight)
end
create_restrictions do |timeslot|
timeslot.ends_at > datetime
end
end

def restrict_before(datetime, weight=1, event=Event.current_event)
event.timeslots.each do |timeslot|
if timeslot.starts_at < datetime
self.presenter_timeslot_restrictions.create!(
timeslot: timeslot,
weight: weight)
end
create_restrictions do |timeslot|
timeslot.starts_at < datetime
end
end

def restrict_not_at(datetime, weight=1, event=Event.current_event)
event.timeslots.each do |timeslot|
if timeslot.ends_at < datetime || timeslot.starts_at > datetime
self.presenter_timeslot_restrictions.create!(
timeslot: timeslot,
weight: weight)
end
create_restrictions do |timeslot|
timeslot.ends_at < datetime || timeslot.starts_at > datetime
end
end

def restrict_all_except(allowed_slots, weight=1, event=Event.current_event)
create_restrictions do |timeslot|
!allowed_slots.include?(timeslot)
end
end

def restrict_to_only(allowed_slots, weight=1, event=Event.current_event)
def restrict_only(disallowed_slots, weight=1, event=Event.current_event)
create_restrictions do |timeslot|
disallowed_slots.include?(timeslot)
end
end

private

def create_restrictions(weight=1, &is_restricted)
event.timeslots.each do |timeslot|
unless allowed_slots.include?(timeslot)
if timeslot.schedulable && yield(timeslot)
self.presenter_timeslot_restrictions.create!(
timeslot: timeslot,
weight: weight)
end
end
end

public

def deliver_password_reset_instructions!
reset_perishable_token!
Notifier.password_reset_instructions(self).deliver_now!
Expand Down
13 changes: 12 additions & 1 deletion bin/schedule
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/bash

set -e

if [ "$#" -ne 2 ]; then
echo "usage: $0 <input constraints.csv> <ouput schedule.json>"
exit 1
Expand All @@ -23,6 +25,11 @@ function section {
section "Pulling latest data from production..."
bin/pull-database-from-production

if [ -e "$schedule_file" ]; then
section "Re-importing previous best schedule..."
rails app:import_schedule <"$schedule_file"
fi

section "Scheduler input quality analysis"
rails db:migrate && rails app:analyze_scheduler_input_quality

Expand All @@ -36,11 +43,15 @@ for q in 0.01 0.05 0.1 0.2 0.3 0.5 0.7 0.9 1.0 1.5; do
done

section "Exporting generated schedule to $schedule_file"
rails app:export_schedule >$schedule_file || exit
rails app:export_schedule >"$schedule_file" || exit

section "Congratulations. You have a schedule!"
echo "Check the schedule locally. If it looks good, you can upload it to prod with:"
echo
echo " heroku run rails app:import_schedule < $schedule_file"
echo -e " ${red_bold}⬆︎⬆︎⬆︎ DANGER: overwrites current live schedule ⬆︎⬆︎⬆︎${normal}"
echo
echo "If you want to try for an even better schedule, you can run this script again."
echo "It will restart from the previous best schedule in $schedule.json."
echo "This is a good idea if you were still seeing “New best solution” even at the"
echo "highest cooling times, late in the process."
20 changes: 12 additions & 8 deletions lib/tasks/app.rake
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ namespace :app do
if args[:config_file].blank?
STDERR.puts 'Usage:

rake app:configure_sessions[path/to/constraints.csv]
rails "app:configure_sessions[path/to/constraints.csv]"

The CSV file must open with a header line with the following columns:

Expand All @@ -118,7 +118,8 @@ namespace :app do
<12:00pm Session must end at or before the given time
>1:00pm, <3:00pm Session must fall entirely within give time range
@2:00pm Session must be in the timeslot that includes the given time
# 1 2 3 Session must be in one of these specific timeslot ids
#= 1 2 3 Session must be in one of these specific timeslot ids
#! 1 2 3 Session must NOT be in one of these specific timeslot ids
manual Do not let sessionizer schedule this session
delete Soft-delete session by assigning to a nonexistent event

Expand Down Expand Up @@ -192,11 +193,14 @@ namespace :app do
constraints.split(',').map(&:strip).each do |constraint|
puts " #{constraint}"

if /^#(?<ids>(\s*\d+\s*)+)$/ =~ constraint
presenter.restrict_to_only(
Timeslot.find(
ids.split))
next
if /^#(?<include_exclude>.)(?<ids>(\s*\d+\s*)+)$/ =~ constraint
specific_slots = Timeslot.find(ids.split)
case include_exclude
when '=' then presenter.restrict_all_except(specific_slots)
when '!' then presenter.restrict_only(specific_slots)
else raise "Unknown include/exclude symbol `#{include_exclude}` in `#{constraint}`"
end
next # done with this rule!
end

unless %r{
Expand Down Expand Up @@ -461,7 +465,7 @@ namespace :app do
puts "#{' ' * timeslots.count} vot exp ID title presenters"
puts "#{' ' * timeslots.count} --- --- ---------------------------------------- ----------"
Session.largest_attendance_first(event.sessions).each do |session|
puts "%s %3d %3s%s %-40.40s %s" % [
puts "%s %3d %3.0f%s %-40.40s %s" % [
timeslots.map { |slot| slot.id == session.timeslot_id ? '•' : ' ' }.join,
session.attendance_count,
session.expected_attendance,
Expand Down
Loading