Schedule maker, stats, and minor fixes

This commit is contained in:
Godwin
2016-07-05 22:40:53 -07:00
parent ee3b874110
commit 26f9dfde89
18 changed files with 913 additions and 184 deletions
+281 -22
View File
@@ -798,6 +798,39 @@ class ConferencesController < ApplicationController
@page_title = 'articles.conference_registration.headings.Administration'
case @admin_step.to_sym
when :stats
@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id)
if request.format.xlsx?
logger.info "Generating stats.xls"
@excel_data = {
columns: [:name, :email, :city, :date, :languages],
column_types: {date: :date},
keys: {
name: 'forms.labels.generic.name',
email: 'forms.labels.generic.email',
city: 'forms.labels.generic.location',
date: 'articles.conference_registration.terms.Date',
languages: 'articles.conference_registration.terms.Languages'
},
data: [],
}
@registrations.each do | r |
user = r.user_id ? User.where(id: r.user_id).first : nil
if user.present?
@excel_data[:data] << {
name: user.firstname || '',
email: user.email || '',
date: r.created_at ? r.created_at.strftime("%F %T") : '',
city: r.city || '',
languages: ((r.languages || []).map { |x| view_context.language x }).join(', ').to_s
}
end
end
return respond_to do | format |
# format.html
format.xlsx { render xlsx: :stats, filename: "stats-#{DateTime.now.strftime('%Y-%m-%d')}" }
end
end
when :housing
# do a full analysis
analyze_housing
@@ -811,6 +844,13 @@ class ConferencesController < ApplicationController
@length = 1.5
when :meals
@meals = Hash[@this_conference.meals.map{ |k, v| [k.to_i, v] }].sort.to_h
when :workshop_times
get_block_data
@workshop_blocks << {
'time' => nil,
'length' => 1.0,
'days' => []
}
when :schedule
get_scheule_data
end
@@ -820,22 +860,8 @@ class ConferencesController < ApplicationController
end
def get_scheule_data
@meals = Hash[@this_conference.meals.map{ |k, v| [k.to_i, v] }].sort.to_h
@events = Event.where(:conference_id => @this_conference.id).order(start_time: :asc)
@workshops = Workshop.where(:conference_id => @this_conference.id).order(start_time: :asc)
@locations = {}
def get_block_data
@workshop_blocks = @this_conference.workshop_blocks || []
@workshop_blocks << {
'time' => nil,
'length' => 1.0,
'days' => []
}
@workshops.each do |workshop|
if workshop.location_id
@locations[workshop.location_id] ||= workshop.location
end
end
@block_days = []
day = @this_conference.start_date
while day <= @this_conference.end_date
@@ -844,6 +870,168 @@ class ConferencesController < ApplicationController
end
end
def get_scheule_data
@meals = Hash[@this_conference.meals.map{ |k, v| [k.to_i, v] }].sort.to_h
@events = Event.where(:conference_id => @this_conference.id).order(start_time: :asc)
@workshops = Workshop.where(:conference_id => @this_conference.id).order(start_time: :asc)
@locations = {}
get_block_data
@schedule = {}
day_1 = @this_conference.start_date.wday
@workshop_blocks.each_with_index do | info, block |
info['days'].each do | block_day |
day_diff = block_day.to_i - day_1
day_diff += 7 if day_diff < 0
day = (@this_conference.start_date + day_diff.days).to_date
time = info['time'].to_f
@schedule[day] ||= { times: {}, locations: {} }
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :workshop
@schedule[day][:times][time][:length] = info['length'].to_f
@schedule[day][:times][time][:item] = { block: block, workshops: {} }
end
end
@workshops.each do | workshop |
if workshop.block.present?
block = @workshop_blocks[workshop.block['block'].to_i]
day_diff = workshop.block['day'].to_i - day_1
day_diff += 7 if day_diff < 0
day = (@this_conference.start_date + day_diff.days).to_date
if @schedule[day].present? && @schedule[day][:times].present? && @schedule[day][:times][block['time'].to_f].present?
@schedule[day][:times][block['time'].to_f][:item][:workshops][workshop.event_location_id] = { workshop: workshop, status: { errors: [], warnings: [], conflict_score: nil } }
@schedule[day][:locations][workshop.event_location_id] ||= workshop.event_location
end
end
end
@meals.each do | time, meal |
day = meal['day'].to_date
time = meal['time'].to_f
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :meal
@schedule[day][:times][time][:length] = (meal['length'] || 1.0).to_f
@schedule[day][:times][time][:item] = meal
end
@events.each do | event |
day = event.start_time.midnight.to_date
time = event.start_time.hour.to_f + (event.start_time.min / 60.0)
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :event
@schedule[day][:times][time][:length] = (event.end_time - event.start_time) / 3600.0
@schedule[day][:times][time][:item] = event
end
@schedule = @schedule.sort.to_h
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
end
@schedule.each do | day, data |
last_event = nil
data[:times].each do | time, time_data |
if last_event.present?
@schedule[day][:times][last_event][:next_event] = time
end
last_event = time
end
end
@schedule.deep_dup.each do | day, data |
data[:times].each do | time, time_data |
if time_data[:next_event].present? || time_data[:length] > 0.5
span = 0.5
length = time_data[:next_event].present? ? time_data[:next_event] - time : time_data[:length]
while span < length
@schedule[day][:times][time + span] ||= {
type: (span >= time_data[:length] ? :empty : :nil),
length: 0.5
}
span += 0.5
end
end
end
end
@schedule = @schedule.sort.to_h
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
data[:times].each do | time, time_data |
if time_data[:type] == :workshop && time_data[:item].present? && time_data[:item][:workshops].present?
ids = time_data[:item][:workshops].keys
(0..ids.length).each do | i |
if time_data[:item][:workshops][ids[i]].present?
workshop_i = time_data[:item][:workshops][ids[i]][:workshop]
conflicts = {}
(i+1..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present?
workshop_i.active_facilitators.each do | facilitator_i |
workshop_j.active_facilitators.each do | facilitator_j |
if facilitator_i.id == facilitator_j.id
@schedule[day][:times][time][:status] ||= {}
@schedule[day][:times][time][:item][:workshops][ids[j]][:status][:errors] << {
name: :common_facilitator,
facilitator: facilitator_i,
workshop: workshop_i,
i18nVars: {
facilitator_name: facilitator_i.name,
workshop_title: workshop_i.title
}
}
end
end
end
end
end
(0..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present? && workshop_i.id != workshop_j.id
workshop_i.interested.each do | interested_i |
workshop_j.interested.each do | interested_j |
conflicts[interested_i.id] ||= true
end
end
end
end
needs = JSON.parse(workshop_i.needs || '[]').map &:to_sym
amenities = JSON.parse(workshop_i.event_location.amenities || '[]').map &:to_sym
needs.each do | need |
@schedule[day][:times][time][:item][:workshops][ids[i]][:status][:errors] << {
name: :need_not_available,
need: need,
location: workshop_i.event_location,
workshop: workshop_i,
i18nVars: {
need: need.to_s,
location: workshop_i.event_location.title,
workshop_title: workshop_i.title
}
} unless amenities.include? need
end
@schedule[day][:times][time][:item][:workshops][ids[i]][:status][:conflict_score] = workshop_i.interested.present? ? (conflicts.length / workshop_i.interested.size) : 0
end
end
end
end
end
end
def get_housing_data
@hosts = {}
@guests = {}
@@ -948,13 +1136,24 @@ class ConferencesController < ApplicationController
case params[:admin_step]
when 'edit'
@this_conference.info = LinguaFranca::ActiveRecord::UntranslatedValue.new(params[:info]) unless @this_conference.info! == params[:info]
case params[:button]
when 'save'
@this_conference.info = LinguaFranca::ActiveRecord::UntranslatedValue.new(params[:info]) unless @this_conference.info! == params[:info]
params[:info_translations].each do | locale, value |
@this_conference.set_column_for_locale(:info, locale, value, current_user.id) unless value = @this_conference._info(locale)
params[:info_translations].each do | locale, value |
@this_conference.set_column_for_locale(:info, locale, value, current_user.id) unless value = @this_conference._info(locale)
end
@this_conference.save
return redirect_to register_step_path(@this_conference.slug, :administration)
when 'add_member'
org = nil
@this_conference.organizations.each do | organization |
org = organization if organization.id == params[:org_id].to_i
end
org.users << (User.get params[:email])
org.save
return redirect_to administration_step_path(@this_conference.slug, :edit)
end
@this_conference.save
return redirect_to register_step_path(@this_conference.slug, :administration)
when 'housing'
space = params[:button].split(':')[0]
host_id = params[:button].split(':')[1].to_i
@@ -1091,7 +1290,7 @@ class ConferencesController < ApplicationController
return redirect_to administration_step_path(@this_conference.slug, :events)
end
when 'schedule'
when 'workshop_times'
case params[:button]
when 'save_block'
@this_conference.workshop_blocks ||= []
@@ -1101,7 +1300,67 @@ class ConferencesController < ApplicationController
'days' => params[:days].keys
}
@this_conference.save
return redirect_to administration_step_path(@this_conference.slug, :schedule)
return redirect_to administration_step_path(@this_conference.slug, :workshop_times)
end
when 'schedule'
success = false
case params[:button]
when 'schedule_workshop'
workshop = Workshop.find_by!(conference_id: @this_conference.id, id: params[:id])
booked = false
workshop.event_location_id = params[:event_location]
block_data = params[:workshop_block].split(':')
workshop.block = {
day: block_data[0].to_i,
block: block_data[1].to_i
}
# make sure this spot isn't already taken
Workshop.where(:conference_id => @this_conference.id).each do | w |
if request.xhr?
if w.block.present? &&
w.id != workshop.id &&
w.block['day'] == workshop.block['day'] &&
w.block['block'] == workshop.block['block'] &&
w.event_location_id == workshop.event_location_id
return render json: [ {
selector: '.already-booked',
className: 'already-booked is-true'
} ]
end
else
return redirect_to administration_step_path(@this_conference.slug, :schedule)
end
end
workshop.save!
success = true
when 'deschedule_workshop'
workshop = Workshop.find_by!(conference_id: @this_conference.id, id: params[:id])
workshop.event_location_id = nil
workshop.block = nil
workshop.save!
success = true
end
if success
if request.xhr?
get_scheule_data
schedule = render_to_string partial: 'conferences/admin/schedule'
return render json: [ {
globalSelector: '#schedule-preview',
html: schedule
}, {
globalSelector: "#workshop-#{workshop.id}",
className: workshop.block.present? ? 'booked' : 'not-booked'
}, {
globalSelector: "#workshop-#{workshop.id} .already-booked",
className: 'already-booked'
} ]
else
return redirect_to administration_step_path(@this_conference.slug, :schedule)
end
end
end
do_404