Implement track scheduling

Add track association to schedule
Show schedules in admin sidebar to track organizers
Allow track organizers to manage the schedules of their tracks
Don't allow self-organized track events to be dragged or unscheduled in
a conference schedule
Make scheduled events of self-organized tracks appear semitransparent in
conference schedules
Make the rooms of confirmed self_organized tracks appear semitransparent
and don't allow events to be scheduled to it in the conference schedules
during the dates of its track
Create admin/SchedulesController#new action
Add a button in admin/Schedules#index to create schedules for tracks
Add self_organized scope to Track
Modify Schedules#show to handle track schedules and show a unified
schedule
Allow track organizers to create new schedules for their tracks
Correctly identify scheduled and unscheduled events in Schedules#events
Fix Event#room and Event#time for when the event is scheduled in a track
schedule
Modify Program#selected_event_schedules to include the event_schedules
of selected track schedules
Modify Track#revoke_role_and_cleanup to destroy the track's schedules
and revert its events' state to new
Add tabs for conference and track schedules in admin/Schedules#index
Add button to Create/Show a tracks schedule in Tracks#index and #show
Fix concurrent_events in application_helper because of changes in
Program#selected_event_schedules
Do not take into account cfp_active in Event#valid_track
Modify EventsController#get_tracks accordingly
Enforce cfp_active of track to be enabled for proposals in
ProposalsController#create and #update
Add support for multiple schedules per track
Add selected_schedule_id to Track
Load EventSchedules of selected track schedules for conference schedules
in admin/SchedulesController#show
Modify SchedulesController#show to take into account only the selected
track schedules
Create Event#selected_schedule_id and use it in Event#scheduled? and
Event#time
Validate that an EventSchedule for an event of a self-organized track
belongs to one of the track's schedules
Add 'Manage' button in Tracks#index, #show that sends you to the admin
side of things
Add admin/TracksController#update_selected_schedule to update the
selected_schedule_id of tracks
This commit is contained in:
AEtherC0r3 2017-08-09 18:12:20 +03:00 committed by Stella Rouzi
parent af7efdb6fe
commit 7eea930269
37 changed files with 443 additions and 118 deletions

View file

@ -188,6 +188,7 @@ linters:
- "app/views/conferences/_call_for_tracks.html.haml" - "app/views/conferences/_call_for_tracks.html.haml"
- "app/views/admin/tracks/_change_state_dropdown.html.haml" - "app/views/admin/tracks/_change_state_dropdown.html.haml"
- "app/views/proposals/_encouragement_text.html.haml" - "app/views/proposals/_encouragement_text.html.haml"
- "app/views/admin/schedules/_form.html.haml"
# Offense count: 223 # Offense count: 223
InstanceVariables: InstanceVariables:
@ -253,6 +254,7 @@ linters:
- "app/views/admin/cfps/_tracks_cfp.html.haml" - "app/views/admin/cfps/_tracks_cfp.html.haml"
- "app/views/conferences/_call_for_tracks.html.haml" - "app/views/conferences/_call_for_tracks.html.haml"
- "app/views/admin/tracks/_change_state_dropdown.html.haml" - "app/views/admin/tracks/_change_state_dropdown.html.haml"
- "app/views/admin/schedules/_form.html.haml"
# Offense count: 32 # Offense count: 32
IdNames: IdNames:

View file

@ -31,3 +31,4 @@ Metrics/BlockLength:
- 'spec/models/conference_spec.rb' - 'spec/models/conference_spec.rb'
- 'spec/features/ability_spec.rb' - 'spec/features/ability_spec.rb'
- 'spec/models/ability_spec.rb' - 'spec/models/ability_spec.rb'
- 'spec/models/admin_ability_spec.rb'

View file

@ -78,11 +78,12 @@ var Schedule = {
}; };
$(document).ready( function() { $(document).ready( function() {
// hide the remove button for unscheduled events // hide the remove button for unscheduled and non schedulable events
$('.unscheduled-events .schedule-event-delete-button').hide(); $('.unscheduled-events .schedule-event-delete-button').hide();
$('.non_schedulable .schedule-event-delete-button').hide();
// set events as draggable // set events as draggable
$('.schedule-event').draggable({ $('.schedule-event').not('.non_schedulable').draggable({
snap: '.schedule-room-slot', snap: '.schedule-room-slot',
revertDuration: 200, revertDuration: 200,
revert: function (event, ui) { revert: function (event, ui) {
@ -99,7 +100,7 @@ $(document).ready( function() {
}); });
// set room cells as droppable // set room cells as droppable
$('.schedule-room-slot').droppable({ $('.schedule-room-slot').not('.non_schedulable .schedule-room-slot').droppable({
accept: '.schedule-event', accept: '.schedule-event',
tolerance: "pointer", tolerance: "pointer",
drop: function(event, ui) { drop: function(event, ui) {

View file

@ -267,6 +267,10 @@ td.no-padding{
font-size: 7px; font-size: 7px;
} }
.non_schedulable{
opacity: 0.5;
}
/* Small devices (tablets, 768px and up) */ /* Small devices (tablets, 768px and up) */
@media (min-width: 768px) { @media (min-width: 768px) {
.room, .event-title{ .room, .event-title{

View file

@ -198,7 +198,7 @@ module Admin
end end
def get_tracks def get_tracks
@tracks = Track.accessible_by(current_ability).where(program: @program).confirmed.cfp_active @tracks = Track.accessible_by(current_ability).where(program: @program).confirmed
end end
end end
end end

View file

@ -4,14 +4,21 @@ module Admin
# the schedule of a conference, which should not be accessed in the first place # the schedule of a conference, which should not be accessed in the first place
load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :conference, find_by: :short_title
load_and_authorize_resource :program, through: :conference, singleton: true load_and_authorize_resource :program, through: :conference, singleton: true
load_and_authorize_resource :schedule, through: :program load_and_authorize_resource :schedule, through: :program, except: [:new, :create]
load_resource :event_schedules, through: :schedule load_resource :event_schedules, through: :schedule
load_resource :selected_schedule, through: :program, singleton: true load_resource :selected_schedule, through: :program, singleton: true
load_resource :venue, through: :conference, singleton: true load_resource :venue, through: :conference, singleton: true
def index; end def index; end
def new
@schedule = @program.schedules.build(track: @program.tracks.new)
authorize! :new, @schedule
end
def create def create
@schedule = @program.schedules.new(schedule_params)
authorize! :create, @schedule
if @schedule.save if @schedule.save
redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id), redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id),
notice: 'Schedule was successfully created.' notice: 'Schedule was successfully created.'
@ -23,9 +30,23 @@ module Admin
def show def show
@event_schedules = @schedule.event_schedules @event_schedules = @schedule.event_schedules
@unscheduled_events = @program.events.confirmed - @schedule.events
@dates = @conference.start_date..@conference.end_date if @schedule.track
@rooms = @conference.venue.rooms if @conference.venue track = @schedule.track
@unscheduled_events = track.events.confirmed - @schedule.events
@dates = track.start_date..track.end_date
@rooms = [track.room]
else
@program.tracks.self_organized.confirmed.each do |t|
@event_schedules += t.selected_schedule.event_schedules if t.selected_schedule
end
self_organized_tracks_events = @program.tracks.self_organized.confirmed.map do |t|
t.events.confirmed
end
@unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events.flatten.compact
@dates = @conference.start_date..@conference.end_date
@rooms = @conference.venue.rooms if @conference.venue
end
end end
def destroy def destroy
@ -37,5 +58,11 @@ module Admin
error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}." error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}."
end end
end end
private
def schedule_params
params.require(:schedule).permit(:track_id) if params[:schedule]
end
end end
end end

View file

@ -101,6 +101,18 @@ module Admin
update_state(:cancel, "Track #{@track.name} canceled!") update_state(:cancel, "Track #{@track.name} canceled!")
end end
def update_selected_schedule
if @track.update_attributes(params.require(:track).permit(:selected_schedule_id))
respond_to do |format|
format.js { render json: {} }
end
else
respond_to do |format|
format.js { render json: { errors: "The selected schedule couldn't been updated #{@track.errors.to_a.join('. ')}" }, status: 422 }
end
end
end
private private
def track_params def track_params

View file

@ -49,6 +49,13 @@ class ProposalsController < ApplicationController
# by default. # by default.
@event.speakers = [current_user] @event.speakers = [current_user]
@event.submitter = current_user @event.submitter = current_user
if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
render action: 'new'
return
end
if @event.save if @event.save
ahoy.track 'Event submission', title: 'New submission' ahoy.track 'Event submission', title: 'New submission'
redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.' redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.'
@ -61,6 +68,12 @@ class ProposalsController < ApplicationController
def update def update
@url = conference_program_proposal_path(@conference.short_title, params[:id]) @url = conference_program_proposal_path(@conference.short_title, params[:id])
if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
render action: 'edit'
return
end
if @event.update(event_params) if @event.update(event_params)
redirect_to conference_program_proposals_path(conference_id: @conference.short_title), redirect_to conference_program_proposals_path(conference_id: @conference.short_title),
notice: 'Proposal was successfully updated.' notice: 'Proposal was successfully updated.'

View file

@ -24,6 +24,13 @@ class SchedulesController < ApplicationController
return unless @current_day return unless @current_day
# the schedule takes you to the current time if it is beetween the start and the end time. # the schedule takes you to the current time if it is beetween the start and the end time.
@hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour)
# Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id
@selected_schedules_ids = [@conference.program.selected_schedule_id]
@conference.program.tracks.self_organized.confirmed.each do |track|
@selected_schedules_ids << track.selected_schedule_id
end
@selected_schedules_ids.compact!
end end
def events def events
@ -32,11 +39,7 @@ class SchedulesController < ApplicationController
@events_schedules = @program.selected_event_schedules @events_schedules = @program.selected_event_schedules
@events_schedules = [] unless @events_schedules @events_schedules = [] unless @events_schedules
@unscheduled_events = if @program.selected_schedule @unscheduled_events = @program.events.confirmed - @events_schedules.map(&:event)
@program.events.confirmed - @program.selected_schedule.events
else
@program.events.confirmed
end
day = @conference.current_conference_day day = @conference.current_conference_day
@tag = day.strftime('%Y-%m-%d') if day @tag = day.strftime('%Y-%m-%d') if day

View file

@ -117,7 +117,7 @@ module ApplicationHelper
def concurrent_events(event) def concurrent_events(event)
return nil unless event.scheduled? && event.program.selected_event_schedules return nil unless event.scheduled? && event.program.selected_event_schedules
event_schedule = event.program.selected_event_schedules.find_by(event: event) event_schedule = event.program.selected_event_schedules.find { |es| es.event == event }
other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule } other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule }
concurrent_events = [] concurrent_events = []

View file

@ -307,5 +307,18 @@ class AdminAbility
can :manage, Event, track_id: track_ids_for_track_organizer can :manage, Event, track_id: track_ids_for_track_organizer
can :manage, Commercial, commercialable_type: 'Event', can :manage, Commercial, commercialable_type: 'Event',
commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id) commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id)
# Show Scheduless in the admin sidebar
can :update, Schedule do |schedule|
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id)
end
# Show new track schedule button
can :new, Schedule do |schedule|
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id) && schedule.track.try(:new_record?)
end
can :manage, Schedule, track_id: track_ids_for_track_organizer
can :manage, EventSchedule, schedule: { track_id: track_ids_for_track_organizer }
end end
end end

View file

@ -45,7 +45,7 @@ class Event < ActiveRecord::Base
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true } validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
validate :max_attendees_no_more_than_room_size validate :max_attendees_no_more_than_room_size
validate :acceptable_track validate :valid_track
scope :confirmed, -> { where(state: 'confirmed') } scope :confirmed, -> { where(state: 'confirmed') }
scope :canceled, -> { where(state: 'canceled') } scope :canceled, -> { where(state: 'canceled') }
@ -85,7 +85,7 @@ class Event < ActiveRecord::Base
# ====Returns # ====Returns
# * +true+ or +false+ # * +true+ or +false+
def scheduled? def scheduled?
event_schedules.find_by(schedule_id: program.selected_schedule_id).present? event_schedules.find_by(schedule_id: selected_schedule_id).present?
end end
def registration_possible? def registration_possible?
@ -243,14 +243,18 @@ class Event < ActiveRecord::Base
def room def room
# We use try(:selected_schedule_id) because this function is used for # We use try(:selected_schedule_id) because this function is used for
# validations so program could not be present there # validations so program could not be present there
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room) if track.try(:self_organized?)
track.room
else
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
end
end end
## ##
# Returns the start time at which this event is scheduled # Returns the start time at which this event is scheduled
# #
def time def time
event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time) event_schedules.find_by(schedule_id: selected_schedule_id).try(:start_time)
end end
def conference def conference
@ -306,9 +310,23 @@ class Event < ActiveRecord::Base
end end
## ##
# Allow only confirmed tracks that belong to the same program and are included in the cfp # Allow only confirmed tracks that belong to the same program as the event
def acceptable_track #
def valid_track
return unless track && track.program && program return unless track && track.program && program
errors.add(:track, 'is invalid') unless track.confirmed? && track.cfp_active && track.program == program errors.add(:track, 'is invalid') unless track.confirmed? && track.program == program
end
##
# Return the id of the selected schedule
#
# ====Returns
# * +Integer+ -> selected_schedule_id of self-organized track or program
def selected_schedule_id
if track.try(:self_organized?)
track.selected_schedule_id
else
program.selected_schedule_id
end
end end
end end

View file

@ -12,8 +12,9 @@ class EventSchedule < ActiveRecord::Base
validates :event, uniqueness: { scope: :schedule } validates :event, uniqueness: { scope: :schedule }
validate :start_after_end_hour validate :start_after_end_hour
validate :start_before_start_hour validate :start_before_start_hour
validate :room_of_track validate :same_room_as_track
validate :during_track validate :during_track
validate :valid_schedule
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') } scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') } scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
@ -56,24 +57,33 @@ class EventSchedule < ActiveRecord::Base
end end
## ##
# Validates that the event is scheduled in the same room as it's track # Validates that the event is scheduled in the same room as its track
# #
def room_of_track def same_room_as_track
if event && event.track.try(:room) && event.track.room != room return unless event.try(:track).try(:room)
errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") unless event.track.room == room
end
##
# Validates that the event is scheduled within its track's time slot
#
def during_track
return unless event.try(:track) && start_time
if event.track.try(:start_date) && event.track.start_date > start_time
errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})")
end
if event.track.try(:end_date) && event.track.end_date + 1.day < end_time
errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})")
end end
end end
## ##
# Validates that the event is scheduled within it's track's time slot # Validates that the event is scheduled in its self-organized tracks's schedules
# #
def during_track def valid_schedule
if event && event.track.try(:start_date) && event.track.start_date > start_time return unless event.try(:track).try(:self_organized?) && schedule
errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})") errors.add(:schedule, "must be one of #{event.track.name} track's schedules") unless event.track.schedules.include?(schedule)
end
if event && event.track.try(:end_date) && event.track.end_date + 1.day < end_time
errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})")
end
end end
end end

View file

@ -71,7 +71,11 @@ class Program < ActiveRecord::Base
# Returns all event_schedules for the selected schedule ordered by start_time # Returns all event_schedules for the selected schedule ordered by start_time
def selected_event_schedules def selected_event_schedules
selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule event_schedules = selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
tracks.self_organized.confirmed.order(start_date: :asc).each do |track|
event_schedules += track.selected_schedule.event_schedules.order(start_time: :asc) if track.selected_schedule
end
event_schedules.sort_by(&:start_time) if event_schedules
end end
## ##

View file

@ -1,5 +1,6 @@
class Schedule < ActiveRecord::Base class Schedule < ActiveRecord::Base
belongs_to :program belongs_to :program
belongs_to :track
has_many :event_schedules, dependent: :destroy has_many :event_schedules, dependent: :destroy
has_many :events, through: :event_schedules has_many :events, through: :event_schedules

View file

@ -7,7 +7,9 @@ class Track < ActiveRecord::Base
belongs_to :program belongs_to :program
belongs_to :submitter, class_name: 'User' belongs_to :submitter, class_name: 'User'
belongs_to :room belongs_to :room
belongs_to :selected_schedule, class_name: 'Schedule'
has_many :events, dependent: :nullify has_many :events, dependent: :nullify
has_many :schedules
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
@ -38,6 +40,7 @@ class Track < ActiveRecord::Base
scope :accepted, -> { where(state: 'accepted') } scope :accepted, -> { where(state: 'accepted') }
scope :confirmed, -> { where(state: 'confirmed') } scope :confirmed, -> { where(state: 'confirmed') }
scope :cfp_active, -> { where(cfp_active: true) } scope :cfp_active, -> { where(cfp_active: true) }
scope :self_organized, -> { where.not(submitter: nil) }
state_machine initial: :pending do state_machine initial: :pending do
state :new state :new
@ -102,7 +105,10 @@ class Track < ActiveRecord::Base
submitter.add_role 'track_organizer', self submitter.add_role 'track_organizer', self
end end
# Revokes the track organizer role and removes the track from events that have it set ##
# Revokes the track organizer role, destroys the track's schedule, removes the
# track from events that have it set and reverts their state to new
#
def revoke_role_and_cleanup def revoke_role_and_cleanup
role = Role.find_by(name: 'track_organizer', resource: self) role = Role.find_by(name: 'track_organizer', resource: self)
@ -112,8 +118,14 @@ class Track < ActiveRecord::Base
end end
end end
self.selected_schedule_id = nil
save!
schedules.each(&:destroy!)
events.each do |event| events.each do |event|
event.track = nil event.track = nil
event.state = 'new'
event.save! event.save!
end end
end end

View file

@ -5,7 +5,9 @@
- date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date } - date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date }
.row .row
- @rooms.each do |room| - @rooms.each do |room|
.col-md-2.col-xs-6 - non_schedulable = room.tracks.self_organized.confirmed.any? do |track|
- !track.schedules.include?(@schedule) && (track.start_date..track.end_date).include?(date)
.col-md-2.col-xs-6{ class: ('non_schedulable' if non_schedulable) }
.room-name .room-name
- room_date_event_schedules = date_event_schedules.select{ |e| e.room == room } - room_date_event_schedules = date_event_schedules.select{ |e| e.room == room }
= room.name = room.name

View file

@ -7,12 +7,13 @@
/ subtracting the padding before calculate the number of lines / subtracting the padding before calculate the number of lines
- lines = (height - 7) / 23 - lines = (height - 7) / 23
- color = event.track.try(:color).present? ? event.track.try(:color) : 'FFFFFF' - color = event.track.try(:color).present? ? event.track.try(:color) : 'FFFFFF'
- non_schedulable = event_schedule_id && (EventSchedule.find(event_schedule_id).schedule != @schedule)
.schedule-event{ style: "height: #{height}px; background-color: #{color}; color: #{contrast_color(color)}", | .schedule-event{ style: "height: #{height}px; background-color: #{color}; color: #{contrast_color(color)}", |
id: "event-#{event.id}", | id: "event-#{event.id}", |
event_id: event.id, | event_id: event.id, |
length: cells_length, | length: cells_length, |
event_schedule_id: event_schedule_id, | event_schedule_id: event_schedule_id, |
class: ('compact' if compact_grid) } class: "#{'compact' if compact_grid} #{'non_schedulable' if non_schedulable}" }
.schedule-event-text{ style: "-webkit-line-clamp: #{lines}; height: #{lines * 23}px;"} .schedule-event-text{ style: "-webkit-line-clamp: #{lines}; height: #{lines * 23}px;"}
%span.schedule-event-delete-button{ onclick: "Schedule.remove(\'event-#{event.id}\');" } X %span.schedule-event-delete-button{ onclick: "Schedule.remove(\'event-#{event.id}\');" } X
= event.title = event.title

View file

@ -0,0 +1,10 @@
.row
.col-md-12
.page-header
%h1
New Track Schedule
.row
.col-md-12
= semantic_form_for @schedule, url: admin_conference_schedules_path(@conference.short_title) do |f|
= f.input :track, collection: Track.accessible_by(current_ability).where(program: @program).self_organized.confirmed.pluck(:name, :id), include_blank: false
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -4,42 +4,85 @@
%h1 Schedules %h1 Schedules
%p.text-muted %p.text-muted
The schedules for your conference The schedules for your conference
.row .tabbable
.col-md-12 %ul.nav.nav-tabs
%table.table.table-hover#event_types %li.active
%thead = link_to 'Conference schedules', '#conference', 'data-toggle' => 'tab'
%th Schedule %li
%th Selected = link_to 'Track schedules', '#tracks', 'data-toggle' => 'tab'
%th Actions .tab-content
%tbody .tab-pane.active#conference
- @schedules.each do |schedule| .row
%tr .col-md-12
%td %table.table.table-hover
Schedule %thead
= schedule.id %th Schedule
%td %th Selected
= selected_scheduled?(schedule) %th Actions
%td %tbody
.btn-group{role: "group"} - @schedules.where(track: nil).each do |schedule|
= link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule.id), %tr
method: :get, class: 'btn btn-primary' %td
= link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule.id), Schedule
method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" } = schedule.id
.row %td
.col-md-12 = selected_scheduled?(schedule)
- if @venue.try(:rooms).present? %td
.text-right .btn-group{role: "group"}
= link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title), - if can? :show, schedule
method: :post, class: 'btn btn-primary' = link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule),
- elsif @venue method: :get, class: 'btn btn-primary'
.h3 - if can? :destroy, schedule
No Rooms! = link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule),
%small method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" }
= link_to 'Create rooms', admin_conference_venue_rooms_path .row
before creating the schedule. .col-md-12
- else - if @venue.try(:rooms).present?
.h3 .text-right
No Venue! - if can? :create, @program.schedules.new
%small = link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title),
= link_to 'Create a venue with rooms', new_admin_conference_venue_path method: :post, class: 'btn btn-primary'
before creating the schedule. - elsif @venue
.h3
No Rooms!
%small
= link_to 'Create rooms', admin_conference_venue_rooms_path
before creating the schedule.
- else
.h3
No Venue!
%small
= link_to 'Create a venue with rooms', new_admin_conference_venue_path
before creating the schedule.
.tab-pane#tracks
.row
.col-md-12
%table.table.table-hover
%thead
%th Schedule
%th Track
%th Selected
%th Actions
%tbody
- @schedules.where.not(track: nil).each do |schedule|
%tr
%td
Schedule
= schedule.id
%td
- track = schedule.track
= link_to track.name, admin_conference_program_track_path(@conference.short_title, track)
%td
= schedule == schedule.track.selected_schedule ? 'Yes' : 'No'
%td
.btn-group{role: "group"}
- if can? :show, schedule
= link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule), class: 'btn btn-primary'
- if can? :destroy, schedule
= link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule),
method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" }
.row
.col-md-12
.text-right
- if can? :new, @program.schedules.build(track: @program.tracks.new)
= link_to 'Add Track Schedule', new_admin_conference_schedule_path(@conference.short_title), class: 'btn btn-primary'

View file

@ -11,8 +11,15 @@
.row .row
.col-md-2 .col-md-2
Selected schedule Selected schedule
= check_box_tag @conference.short_title, @schedule.id, (@schedule.id == @selected_schedule.try(:id)), :ruby
method: :patch, url: (admin_conference_program_path(@conference.short_title) + '?[program][selected_schedule_id]='), if @schedule.track
value = @schedule == @schedule.track.selected_schedule
url = update_selected_schedule_admin_conference_program_track_path(@conference.short_title, @schedule.track) + '?[track][selected_schedule_id]='
else
value = @schedule.id == @selected_schedule.try(:id)
url = admin_conference_program_path(@conference.short_title) + '?[program][selected_schedule_id]='
end
= check_box_tag @conference.short_title, @schedule.id, value, method: :patch, url: url,
class: 'switch-checkbox-schedule', data: { size: 'small', class: 'switch-checkbox-schedule', data: { size: 'small',
off_color: 'warning', off_color: 'warning',
on_text: 'Yes', on_text: 'Yes',

View file

@ -63,9 +63,19 @@
.btn-group{role: "group"} .btn-group{role: "group"}
- if can? :edit, track - if can? :edit, track
= link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary'
- special_style = true
- if can? :destroy, track - if can? :destroy, track
= link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger',
data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" }
- if track.self_organized?
- if track.selected_schedule
- if can? :show, track.selected_schedule
= link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule),
class: 'btn btn-default'
- elsif can? :create, @program.schedules.build(track: track)
= button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title),
form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default',
style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id }
.row .row
.col-md-12.text-right .col-md-12.text-right
= link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success' = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success'

View file

@ -21,10 +21,20 @@
- if can? :edit, @track - if can? :edit, @track
= link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, @track), = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, @track),
method: :get, class: 'btn btn-primary' method: :get, class: 'btn btn-primary'
- special_style = true
- if can? :destroy, @track - if can? :destroy, @track
= link_to 'Delete', admin_conference_program_track_path(@conference.short_title, @track), = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, @track),
method: :delete, class: 'btn btn-danger', method: :delete, class: 'btn btn-danger',
data: { confirm: "Do you really want to delete #{@track.name}? Attention: This track will be removed from all Events that have it set" } data: { confirm: "Do you really want to delete #{@track.name}? Attention: This track will be removed from all Events that have it set" }
- if @track.self_organized?
- if @track.selected_schedule
- if can? :show, @track.selected_schedule
= link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, @track.selected_schedule),
class: 'btn btn-default'
- elsif can? :create, @program.schedules.build(track: @track)
= button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title),
form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default',
style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => @track.id }
.row .row
.col-md-12 .col-md-12
%table.table %table.table

View file

@ -114,7 +114,7 @@
%dl %dl
%dt Start Time: %dt Start Time:
%dd %dd
= event.program.selected_event_schedules.find_by(event: event).start_time.strftime("%Y %B %e %H:%M") = event.program.selected_event_schedules.find { |es| es.event == event }.start_time.strftime("%Y %B %e %H:%M")
%br %br
%dt Room: %dt Room:
%dd %dd

View file

@ -29,7 +29,7 @@
%td.room{ style: "height: #{ td_height(@rooms) }px;" } %td.room{ style: "height: #{ td_height(@rooms) }px;" }
.room.elipsis.break-words{ style: "-webkit-line-clamp: #{ room_lines(@rooms) }; height: #{ room_height(@rooms) }px;" } .room.elipsis.break-words{ style: "-webkit-line-clamp: #{ room_lines(@rooms) }; height: #{ room_height(@rooms) }px;" }
= room.name = room.name
- event_schedules = room.event_schedules.select{ |e| (e.schedule_id == @conference.program.selected_schedule.id) && (e.end_time > start_time) && (e.start_time <= (start_time + hrs_per_slide.hour)) } - event_schedules = room.event_schedules.select{ |e| @selected_schedules_ids.include?(e.schedule_id) && (e.end_time > start_time) && (e.start_time <= (start_time + hrs_per_slide.hour)) }
- (1..intervals).each do |i| - (1..intervals).each do |i|
- if span > 1 - if span > 1
- span -= 1 - span -= 1

View file

@ -72,6 +72,8 @@
method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}" method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}"
- if can? :edit, track - if can? :edit, track
= link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default' = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default'
- if current_user.has_role? :track_organizer, track
= link_to 'Manage', admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default'
.row .row
.col-md-12 .col-md-12

View file

@ -8,6 +8,8 @@
.btn-group.pull-right .btn-group.pull-right
- if can? :edit, @track - if can? :edit, @track
= link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary'
- if current_user.has_role? :track_organizer, @track
= link_to 'Manage', admin_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-default'
.row .row
.col-md-8 .col-md-8
%dl.dl-horizontal %dl.dl-horizontal

View file

@ -40,7 +40,7 @@ Osem::Application.routes.draw do
resources :comments, only: [:index] resources :comments, only: [:index]
resources :conferences do resources :conferences do
resource :contact, except: [:index, :new, :create, :show, :destroy] resource :contact, except: [:index, :new, :create, :show, :destroy]
resources :schedules, only: [:index, :create, :show, :update, :destroy] resources :schedules, except: [:edit, :update]
resources :event_schedules, only: [:create, :update, :destroy] resources :event_schedules, only: [:create, :update, :destroy]
get 'commercials/render_commercial' => 'commercials#render_commercial' get 'commercials/render_commercial' => 'commercials#render_commercial'
resources :commercials, only: [:index, :create, :update, :destroy] resources :commercials, only: [:index, :create, :update, :destroy]
@ -88,6 +88,7 @@ Osem::Application.routes.draw do
patch :to_reject patch :to_reject
patch :reject patch :reject
patch :cancel patch :cancel
patch :update_selected_schedule
end end
end end
resources :event_types resources :event_types

View file

@ -0,0 +1,5 @@
class AddTrackReferenceToSchedule < ActiveRecord::Migration
def change
add_reference :schedules, :track, index: true, foreign_key: true
end
end

View file

@ -0,0 +1,6 @@
class AddSelectedScheduleToTracks < ActiveRecord::Migration
def change
add_column :tracks, :selected_schedule_id, :integer
add_index :tracks, :selected_schedule_id
end
end

View file

@ -431,9 +431,11 @@ ActiveRecord::Schema.define(version: 20170816203325) do
t.integer "program_id" t.integer "program_id"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "track_id"
end end
add_index "schedules", ["program_id"], name: "index_schedules_on_program_id" add_index "schedules", ["program_id"], name: "index_schedules_on_program_id"
add_index "schedules", ["track_id"], name: "index_schedules_on_track_id"
create_table "splashpages", force: :cascade do |t| create_table "splashpages", force: :cascade do |t|
t.integer "conference_id" t.integer "conference_id"
@ -520,24 +522,26 @@ ActiveRecord::Schema.define(version: 20170816203325) do
end end
create_table "tracks", force: :cascade do |t| create_table "tracks", force: :cascade do |t|
t.string "guid", null: false t.string "guid", null: false
t.string "name", null: false t.string "name", null: false
t.text "description" t.text "description"
t.string "color" t.string "color"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.integer "program_id" t.integer "program_id"
t.string "short_name", null: false t.string "short_name", null: false
t.string "state", default: "new", null: false t.string "state", default: "new", null: false
t.boolean "cfp_active", null: false t.boolean "cfp_active", null: false
t.integer "submitter_id" t.integer "submitter_id"
t.integer "room_id" t.integer "room_id"
t.date "start_date" t.date "start_date"
t.date "end_date" t.date "end_date"
t.text "relevance" t.text "relevance"
t.integer "selected_schedule_id"
end end
add_index "tracks", ["room_id"], name: "index_tracks_on_room_id" add_index "tracks", ["room_id"], name: "index_tracks_on_room_id"
add_index "tracks", ["selected_schedule_id"], name: "index_tracks_on_selected_schedule_id"
add_index "tracks", ["submitter_id"], name: "index_tracks_on_submitter_id" add_index "tracks", ["submitter_id"], name: "index_tracks_on_submitter_id"
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|

View file

@ -4,7 +4,7 @@ feature 'Has correct abilities' do
let(:organization) { create(:organization) } let(:organization) { create(:organization) }
let(:conference) { create(:full_conference, organization: organization) } let(:conference) { create(:full_conference, organization: organization) }
let(:self_organized_track) { create(:track, :self_organized, program: conference.program, state: 'confirmed', cfp_active: true) } let(:self_organized_track) { create(:track, :self_organized, program: conference.program, state: 'confirmed') }
let(:role_track_organizer) { Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create } let(:role_track_organizer) { Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create }
let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) } let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) }
@ -32,7 +32,7 @@ feature 'Has correct abilities' do
expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks") expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks")
expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types")
expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels")
expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules")
expect(page).to have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") expect(page).to have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports")
expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations")
expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period")
@ -130,12 +130,16 @@ feature 'Has correct abilities' do
expect(current_path).to eq root_path expect(current_path).to eq root_path
visit admin_conference_schedules_path(conference.short_title) visit admin_conference_schedules_path(conference.short_title)
expect(current_path).to eq root_path expect(current_path).to eq admin_conference_schedules_path(conference.short_title)
create(:schedule, program: conference.program) create(:schedule, program: conference.program)
visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first)
expect(current_path).to eq root_path expect(current_path).to eq root_path
self_organized_track_schedule = create(:schedule, program: conference.program, track: self_organized_track)
visit admin_conference_schedule_path(conference.short_title, self_organized_track_schedule)
expect(current_path).to eq admin_conference_schedule_path(conference.short_title, self_organized_track_schedule)
visit admin_conference_program_reports_path(conference.short_title) visit admin_conference_program_reports_path(conference.short_title)
expect(current_path).to eq admin_conference_program_reports_path(conference.short_title) expect(current_path).to eq admin_conference_program_reports_path(conference.short_title)

View file

@ -45,7 +45,7 @@ describe 'User with admin role' do
let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) }
let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) }
let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed', cfp_active: true) } let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed') }
context 'user #is_admin?' do context 'user #is_admin?' do
let(:venue) { my_conference.venue } let(:venue) { my_conference.venue }
@ -460,8 +460,12 @@ describe 'User with admin role' do
let(:user) { create(:user, role_ids: [role.id]) } let(:user) { create(:user, role_ids: [role.id]) }
let(:new_track) { build(:track, program: my_conference.program) } let(:new_track) { build(:track, program: my_conference.program) }
let(:new_event) { build(:event, program: my_conference.program) } let(:new_event) { build(:event, program: my_conference.program) }
let(:new_schedule) { build(:schedule, program: my_conference.program) }
let(:new_track_schedule) { build(:schedule, program: my_conference.program, track: new_track) }
let(:my_self_organized_track_event) { create(:event, program: my_conference.program, track: my_self_organized_track) } let(:my_self_organized_track_event) { create(:event, program: my_conference.program, track: my_self_organized_track) }
let(:my_self_organized_track_event_commercial) { create(:commercial, commercialable: my_self_organized_track_event) } let(:my_self_organized_track_event_commercial) { create(:commercial, commercialable: my_self_organized_track_event) }
let(:my_self_organized_track_schedule) { create(:schedule, program: my_conference.program, track: my_self_organized_track) }
let(:my_self_organized_track_event_schedule) { create(:event_schedule, event: my_self_organized_track_event, schedule: my_self_organized_track_schedule, room: my_self_organized_track.room) }
it{ should_not be_able_to(:new, Conference.new) } it{ should_not be_able_to(:new, Conference.new) }
it{ should_not be_able_to(:create, Conference.new) } it{ should_not be_able_to(:create, Conference.new) }
@ -532,6 +536,11 @@ describe 'User with admin role' do
it{ should be_able_to(:manage, my_self_organized_track_event) } it{ should be_able_to(:manage, my_self_organized_track_event) }
it{ should be_able_to(:manage, my_self_organized_track_event_commercial) } it{ should be_able_to(:manage, my_self_organized_track_event_commercial) }
it{ should be_able_to(:update, new_schedule) }
it{ should be_able_to(:new, new_track_schedule) }
it{ should be_able_to(:manage, my_self_organized_track_schedule) }
it{ should be_able_to(:manage, my_self_organized_track_event_schedule) }
it_behaves_like 'user with any role' it_behaves_like 'user with any role'
it_behaves_like 'user with non-organizer role', 'track_organizer' it_behaves_like 'user with non-organizer role', 'track_organizer'
end end

View file

@ -46,7 +46,7 @@ describe EventSchedule do
end end
end end
describe '#room_of_track' do describe '#same_room_as_track' do
before :each do before :each do
conference = create(:conference) conference = create(:conference)
conference.venue = create(:venue) conference.venue = create(:venue)
@ -108,5 +108,39 @@ describe EventSchedule do
end end
end end
end end
describe '#valid_schedule' do
before :each do
conference.venue = create(:venue)
@room = create(:room, venue: conference.venue)
track = create(:track, :self_organized, program: conference.program, room: @room, state: 'confirmed', name: 'My awesome track')
@event = create(:event, program: conference.program, track: track)
end
context 'is valid' do
it 'when the event belongs to a self-organized track and is scheduled in one of its track\'s schedules' do
schedule = create(:schedule, program: conference.program, track: @event.track)
event_schedule = build(:event_schedule, event: @event, room: @room, schedule: schedule)
expect(event_schedule.valid?).to eq true
expect(event_schedule.errors[:schedule]).to eq []
end
it 'when the event doesn\'t belong to a self-organized track' do
@event.track = nil
@event.save!
event_schedule = build(:event_schedule, event: @event, room: @room)
expect(event_schedule.valid?).to eq true
expect(event_schedule.errors[:schedule]).to eq []
end
end
context 'is invalid' do
it 'when the event belongs to a self_organized track but isn\'t scheduled in one of its schedules' do
event_schedule = build(:event_schedule, event: @event, room: @room)
expect(event_schedule.valid?).to eq false
expect(event_schedule.errors[:schedule]).to eq ['must be one of My awesome track track\'s schedules']
end
end
end
end end
end end

View file

@ -97,10 +97,10 @@ describe Event do
end end
end end
describe '#acceptable_track' do describe '#valid_track' do
context 'is valid' do context 'is valid' do
it 'when the track belong to the same program, is confirmed and is included in the cfp' do it 'when the track belongs to the same program and is confirmed' do
track = create(:track, state: 'confirmed', cfp_active: true, program: conference.program) track = create(:track, state: 'confirmed', program: conference.program)
event = build(:event, program: conference.program, track: track) event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq true expect(event.valid?).to eq true
end end
@ -108,26 +108,19 @@ describe Event do
context 'is invalid' do context 'is invalid' do
it 'when the track doesn\'t have the same program' do it 'when the track doesn\'t have the same program' do
track = create(:track, state: 'confirmed', cfp_active: true) track = create(:track, state: 'confirmed')
event = build(:event, program: conference.program, track: track) event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid'] expect(event.errors[:track]).to eq ['is invalid']
end end
it 'when the track is unconfirmed' do it 'when the track is unconfirmed' do
track = create(:track, cfp_active: true, program: conference.program) track = create(:track, program: conference.program)
allow(track).to receive(:confirmed?).and_return(false) allow(track).to receive(:confirmed?).and_return(false)
event = build(:event, program: conference.program, track: track) event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid'] expect(event.errors[:track]).to eq ['is invalid']
end end
it 'when the track isn\'t included in the cfp' do
track = create(:track, state: 'confirmed', cfp_active: false, program: conference.program)
event = build(:event, program: conference.program, track: track)
expect(event.valid?).to eq false
expect(event.errors[:track]).to eq ['is invalid']
end
end end
end end
end end
@ -382,4 +375,30 @@ describe Event do
expect(other_event.week).to eq 48 expect(other_event.week).to eq 48
end end
end end
describe '#selected_schedule_id' do
before :each do
conference.program.selected_schedule = create(:schedule, program: conference.program)
end
context 'returns the program\'s selected_schedule_id' do
it 'when it doesn\'t have a track' do
create(:event_schedule, event: event, schedule: conference.program.selected_schedule)
expect(event.send(:selected_schedule_id)).to eq conference.program.selected_schedule_id
end
it 'when it belongs to a regular track' do
event.track = create(:track, program: conference.program)
expect(event.send(:selected_schedule_id)).to eq conference.program.selected_schedule_id
end
end
context 'returns the track\'s selected_schedule_id' do
it 'when it belongs to a self-organized track' do
event.track = create(:track, :self_organized, program: conference.program, state: 'confirmed')
event.track.selected_schedule = create(:schedule, program: conference.program, track: event.track)
expect(event.send(:selected_schedule_id)).to eq event.track.selected_schedule_id
end
end
end
end end

View file

@ -4,6 +4,7 @@ describe Schedule do
describe 'association' do describe 'association' do
it { should belong_to(:program) } it { should belong_to(:program) }
it { should belong_to(:track) }
it { should have_many(:event_schedules).dependent(:destroy) } it { should have_many(:event_schedules).dependent(:destroy) }
it { should have_many(:events).through(:event_schedules) } it { should have_many(:events).through(:event_schedules) }
end end

View file

@ -9,7 +9,9 @@ describe Track do
it { is_expected.to belong_to(:program) } it { is_expected.to belong_to(:program) }
it { is_expected.to belong_to(:submitter).class_name('User') } it { is_expected.to belong_to(:submitter).class_name('User') }
it { is_expected.to belong_to(:room) } it { is_expected.to belong_to(:room) }
it { is_expected.to belong_to(:selected_schedule).class_name('Schedule') }
it { is_expected.to have_many(:events) } it { is_expected.to have_many(:events) }
it { is_expected.to have_many(:schedules) }
end end
describe 'validation' do describe 'validation' do
@ -145,20 +147,20 @@ describe Track do
end end
context 'is valid' do context 'is valid' do
it 'when the tracks are in different rooms' do it 'when the tracks are in different rooms at the same time' do
other_room = create(:room, venue: @conference.venue) other_room = create(:room, venue: @conference.venue)
create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: other_room, start_date: Date.current, end_date: Date.current) create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: other_room, start_date: Date.current, end_date: Date.current)
track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current)
expect(track.valid?).to eq true expect(track.valid?).to eq true
end end
it 'when it ends before the other tracks' do it 'when it ends before the other tracks in the same room' do
create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current)
track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current - 1.day) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current - 1.day)
expect(track.valid?).to eq true expect(track.valid?).to eq true
end end
it 'when it starts after the other tracks' do it 'when it starts after the other tracks in the same room' do
create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current)
track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 1.day) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 1.day)
expect(track.valid?).to eq true expect(track.valid?).to eq true
@ -166,7 +168,7 @@ describe Track do
end end
context 'is invalid' do context 'is invalid' do
it 'when it starts or ends with another track in the same room' do it 'when it starts and/or ends with another track in the same room' do
create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current)
track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current)
expect(track.valid?).to eq false expect(track.valid?).to eq false
@ -264,6 +266,24 @@ describe Track do
expect(@program.tracks.cfp_active.include?(@non_cfp_active_track)).to eq false expect(@program.tracks.cfp_active.include?(@non_cfp_active_track)).to eq false
end end
end end
describe '#self_organized' do
before :each do
@program = create(:program)
track.program = @program
track.save!
self_organized_track.program = @program
self_organized_track.save!
end
it 'includes self-organized tracks' do
expect(@program.tracks.self_organized.include?(self_organized_track)).to eq true
end
it 'excludes regular tracks' do
expect(@program.tracks.self_organized.include?(track)).to eq false
end
end
end end
describe '#self_organized?' do describe '#self_organized?' do
@ -334,7 +354,8 @@ describe Track do
self_organized_track.cfp_active = true self_organized_track.cfp_active = true
self_organized_track.save! self_organized_track.save!
@a_track_organizer.add_role 'track_organizer', self_organized_track @a_track_organizer.add_role 'track_organizer', self_organized_track
@an_event_of_the_track = create(:event, program: self_organized_track.program, track: self_organized_track) @event_of_self_organized_track = create(:event, program: self_organized_track.program, track: self_organized_track, state: 'confirmed')
@schedule_of_self_organized_track = create(:schedule, program: self_organized_track.program, track: self_organized_track)
end end
it 'revokes the role of the track organizer' do it 'revokes the role of the track organizer' do
@ -343,11 +364,24 @@ describe Track do
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
end end
it 'removes the track from the events that have it set' do it 'destroys the track\'s schedules' do
expect(@an_event_of_the_track.track).to eq self_organized_track expect(Schedule.find(@schedule_of_self_organized_track.id)).to eq @schedule_of_self_organized_track
self_organized_track.revoke_role_and_cleanup self_organized_track.revoke_role_and_cleanup
@an_event_of_the_track.reload expect(Schedule.find_by(id: @schedule_of_self_organized_track.id)).to eq nil
expect(@an_event_of_the_track.track).to eq nil end
it 'removes the track from the events that have it set' do
expect(@event_of_self_organized_track.track).to eq self_organized_track
self_organized_track.revoke_role_and_cleanup
@event_of_self_organized_track.reload
expect(@event_of_self_organized_track.track).to eq nil
end
it 'sets the state of the track\'s events to new' do
expect(@event_of_self_organized_track.state).to eq 'confirmed'
self_organized_track.revoke_role_and_cleanup
@event_of_self_organized_track.reload
expect(@event_of_self_organized_track.state).to eq 'new'
end end
it 'is executed when the track is canceled' do it 'is executed when the track is canceled' do
@ -355,15 +389,15 @@ describe Track do
self_organized_track.save! self_organized_track.save!
self_organized_track.cancel self_organized_track.cancel
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
@an_event_of_the_track.reload @event_of_self_organized_track.reload
expect(@an_event_of_the_track.track).to eq nil expect(@event_of_self_organized_track.track).to eq nil
end end
it 'is executed when the track is withdrawn' do it 'is executed when the track is withdrawn' do
self_organized_track.withdraw self_organized_track.withdraw
expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false
@an_event_of_the_track.reload @event_of_self_organized_track.reload
expect(@an_event_of_the_track.track).to eq nil expect(@event_of_self_organized_track.track).to eq nil
end end
end end