Merge pull request #1094 from Ana06/schedule-versioning
Schedule versioning
1
Gemfile
|
|
@ -79,6 +79,7 @@ gem 'cocoon'
|
|||
|
||||
# as the JavaScript library
|
||||
gem 'jquery-rails'
|
||||
gem 'jquery-ui-rails', '~> 4.2.1'
|
||||
|
||||
# for languages validation
|
||||
gem 'iso-639'
|
||||
|
|
|
|||
|
|
@ -226,6 +226,8 @@ GEM
|
|||
jquery-rails (3.1.4)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
jwt (1.0.0)
|
||||
launchy (2.4.2)
|
||||
|
|
@ -567,6 +569,7 @@ DEPENDENCIES
|
|||
iso-639
|
||||
jquery-datatables-rails (~> 2.2.1)
|
||||
jquery-rails
|
||||
jquery-ui-rails (~> 4.2.1)
|
||||
leaflet-rails
|
||||
letter_opener
|
||||
letter_opener_web
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery.mobile.custom.min
|
||||
//= require jquery.ui.draggable
|
||||
//= require jquery.ui.droppable
|
||||
//= require waypoints/jquery.waypoints
|
||||
//= require dataTables/jquery.dataTables
|
||||
//= require dataTables/bootstrap/3/jquery.dataTables.bootstrap
|
||||
|
|
@ -36,6 +38,7 @@
|
|||
//= require osem-datatables
|
||||
//= require osem-tickets
|
||||
//= require bootstrap-switch
|
||||
//= require osem-schedule
|
||||
//= require osem-switch
|
||||
//= require osem-bootstrap
|
||||
//= require osem-commercials
|
||||
|
|
|
|||
118
app/assets/javascripts/osem-schedule.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
var url; // Should be initialize in Schedule.initialize
|
||||
var schedule_id; // Should be initialize in Schedule.initialize
|
||||
|
||||
function showError(error){
|
||||
// Delete other error messages before showing the new one
|
||||
$('.unobtrusive-flash-container').empty();
|
||||
UnobtrusiveFlash.showFlashMessage(error, {type: 'error'});
|
||||
}
|
||||
|
||||
var Schedule = {
|
||||
initialize: function(url_param, schedule_id_param) {
|
||||
url = url_param;
|
||||
schedule_id = schedule_id_param;
|
||||
},
|
||||
remove: function(element) {
|
||||
var e = $("#" + element);
|
||||
var event_schedule_id = e.attr("event_schedule_id");
|
||||
if(event_schedule_id != null){
|
||||
var my_url = url + '/' + event_schedule_id;
|
||||
var success_callback = function(data) {
|
||||
console.log(data);
|
||||
e.attr("event_schedule_id", null);
|
||||
e.appendTo($(".unscheduled-events"));
|
||||
e.find(".schedule-event-delete-button").hide();
|
||||
}
|
||||
var error_callback = function(data) {
|
||||
console.log(data);
|
||||
showError($.parseJSON(data.responseText).errors);
|
||||
}
|
||||
$.ajax({
|
||||
url: my_url,
|
||||
type: 'DELETE',
|
||||
success: success_callback,
|
||||
error: error_callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
}
|
||||
else{
|
||||
showError("The event couldn't be unscheduled");
|
||||
}
|
||||
},
|
||||
add: function (previous_parent, new_parent, event) {
|
||||
event.appendTo(new_parent);
|
||||
var event_schedule_id = event.attr("event_schedule_id");
|
||||
var my_url = url;
|
||||
var type = 'POST';
|
||||
var params = { event_schedule: {
|
||||
room_id: new_parent.attr("room_id"),
|
||||
start_time: (new_parent.attr("date") + ' ' + new_parent.attr("hour"))
|
||||
}};
|
||||
if(event_schedule_id != null){
|
||||
type = 'PUT';
|
||||
my_url += ('/' + event_schedule_id);
|
||||
}
|
||||
else{
|
||||
params['event_schedule']['event_id'] = event.attr("event_id");
|
||||
params['event_schedule']['schedule_id'] = schedule_id;
|
||||
}
|
||||
var success_callback = function(data) {
|
||||
console.log(data);
|
||||
event.attr("event_schedule_id", data.event_schedule_id);
|
||||
event.find(".schedule-event-delete-button").show();
|
||||
}
|
||||
var error_callback = function(data) {
|
||||
console.log(data);
|
||||
showError($.parseJSON(data.responseText).errors);
|
||||
event.appendTo(previous_parent);
|
||||
}
|
||||
$.ajax({
|
||||
url: my_url,
|
||||
type: type,
|
||||
data: params,
|
||||
success: success_callback,
|
||||
error: error_callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready( function() {
|
||||
// hide the remove button for unscheduled events
|
||||
$('.unscheduled-events .schedule-event-delete-button').hide();
|
||||
|
||||
// set events as draggable
|
||||
$('.schedule-event').draggable({
|
||||
snap: '.schedule-room-slot',
|
||||
revertDuration: 200,
|
||||
revert: function (event, ui) {
|
||||
console.log(event.attr);
|
||||
return !event;
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
this._originalPosition = this._originalPosition || ui.originalPosition;
|
||||
ui.helper.animate( this._originalPosition );
|
||||
},
|
||||
opacity: 0.7,
|
||||
snapMode: "inner",
|
||||
zIndex: 2
|
||||
});
|
||||
|
||||
// set room cells as droppable
|
||||
$('.schedule-room-slot').droppable({
|
||||
accept: '.schedule-event',
|
||||
tolerance: "pointer",
|
||||
drop: function(event, ui) {
|
||||
$(ui.draggable).css("left", 0);
|
||||
$(ui.draggable).css("top", 0);
|
||||
$(this).css("background-color", "#ffffff");
|
||||
Schedule.add($(ui.draggable).parent(), $(this), $(ui.draggable));
|
||||
},
|
||||
over: function(event, ui) {
|
||||
$(this).css("background-color", "#009ED8");
|
||||
},
|
||||
out: function(event, ui) {
|
||||
$(this).css("background-color", "#ffffff");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -11,4 +11,25 @@ $(function () {
|
|||
dataType: 'script'
|
||||
});
|
||||
});
|
||||
|
||||
$("[class='switch-checkbox-schedule']").bootstrapSwitch();
|
||||
|
||||
$('input[class="switch-checkbox-schedule"]').on('switchChange.bootstrapSwitch', function(event, state) {
|
||||
var url = $(this).attr('url');
|
||||
var method = $(this).attr('method');
|
||||
|
||||
if(state){
|
||||
url += $(this).attr('value');
|
||||
}
|
||||
|
||||
var callback = function(data) {
|
||||
showError($.parseJSON(data.responseText).errors);
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: method,
|
||||
error: callback,
|
||||
dataType: 'json'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,52 @@
|
|||
|
||||
.room-name{
|
||||
font-weight: bold;
|
||||
padding:10px;
|
||||
margin-top: 30px;
|
||||
border: 1px solid #848484;
|
||||
background-color: #E6E6E6;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
height: 40px;
|
||||
line-height: 25px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.schedule-room-slot{
|
||||
padding: 2px 5px;
|
||||
border: 1px solid #848484;
|
||||
height: 58px;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.schedule-event{
|
||||
padding: 7px;
|
||||
border: 2px solid #151515;
|
||||
position:relative;
|
||||
z-index:1;
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
.schedule-event-text{
|
||||
display: -webkit-box;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 23px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.schedule-event-delete-button {
|
||||
font-weight:bold;
|
||||
cursor: pointer;
|
||||
padding: 0px 3px;
|
||||
border: 1px solid grey;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#schedule td.event {
|
||||
background-image: linear-gradient(bottom, rgb(247,250,242) 24%, rgb(194,232,190) 97%, rgb(194,232,190) 100%);
|
||||
background-image: -o-linear-gradient(bottom, rgb(247,250,242) 24%, rgb(194,232,190) 97%, rgb(194,232,190) 100%);
|
||||
|
|
|
|||
35
app/controllers/admin/event_schedules_controller.rb
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
module Admin
|
||||
class EventSchedulesController < Admin::BaseController
|
||||
load_and_authorize_resource :event_schedule
|
||||
|
||||
def create
|
||||
if @event_schedule.save
|
||||
render json: { event_schedule_id: @event_schedule.id }
|
||||
else
|
||||
render json: { errors: "The event couldn't be scheduled. #{@event_schedule.errors.full_messages.join('. ')}" }, status: 422
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @event_schedule.update(event_schedule_params)
|
||||
render json: { event_schedule_id: @event_schedule.id }
|
||||
else
|
||||
render json: { errors: "The event couldn't be scheduled. #{@event_schedule.errors.full_messages.join('. ')}" }, status: 422
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @event_schedule.destroy
|
||||
render json: {}
|
||||
else
|
||||
render json: { errors: "The event couldn't be unscheduled. #{@event_schedule.errors.full_messages.join('. ')}" }, status: 422
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def event_schedule_params
|
||||
params.require(:event_schedule).permit(:schedule_id, :event_id, :room_id, :start_time)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -191,7 +191,7 @@ module Admin
|
|||
# Set also in proposals controller
|
||||
:title, :subtitle, :event_type_id, :abstract, :description, :require_registration, :difficulty_level_id,
|
||||
# Set only in admin/events controller
|
||||
:track_id, :state, :language, :start_time, :is_highlight, :max_attendees,
|
||||
:track_id, :state, :language, :is_highlight, :max_attendees,
|
||||
# Not used anymore?
|
||||
:proposal_additional_speakers, :user, :users_attributes)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,18 +15,28 @@ module Admin
|
|||
|
||||
if @program.update_attributes(program_params)
|
||||
ConferenceScheduleUpdateMailJob.perform_later(@conference) if send_mail_on_schedule_public
|
||||
redirect_to admin_conference_program_path(@conference.short_title),
|
||||
notice: 'The program was successfully updated.'
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to admin_conference_program_path(@conference.short_title),
|
||||
notice: 'The program was successfully updated.'
|
||||
end
|
||||
format.js { render json: {} }
|
||||
end
|
||||
else
|
||||
flash[:error] = "Updating program failed. #{@program.errors.to_a.join('. ')}."
|
||||
render :new
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
flash[:error] = "Updating program failed. #{@program.errors.to_a.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
format.js { render json: { errors: "The selected schedule couldn't been updated #{@program.errors.to_a.join('. ')}" }, status: 422 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def program_params
|
||||
params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date)
|
||||
params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date, :selected_schedule_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,72 +4,38 @@ module Admin
|
|||
# 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 :program, through: :conference, singleton: true
|
||||
load_and_authorize_resource :schedule, through: :program
|
||||
load_resource :event_schedules, through: :schedule
|
||||
load_resource :selected_schedule, through: :program, singleton: true
|
||||
load_resource :venue, through: :conference, singleton: true
|
||||
|
||||
skip_before_filter :verify_authenticity_token, only: [:update]
|
||||
layout 'schedule'
|
||||
def index; end
|
||||
|
||||
def create
|
||||
if @schedule.save
|
||||
redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id),
|
||||
notice: 'Schedule was successfully created.'
|
||||
else
|
||||
redirect_to admin_conference_schedules_path(conference_id: @conference.short_title),
|
||||
error: "Could not create schedule. #{@schedule.errors.full_messages.join('. ')}."
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
authorize! :update, @program.events.new
|
||||
if @conference.nil?
|
||||
redirect_to admin_conference_index_path
|
||||
return
|
||||
end
|
||||
@event_schedules = @schedule.event_schedules
|
||||
@unscheduled_events = @program.events.confirmed - @schedule.events
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
if @venue && @venue.rooms.any?
|
||||
@rooms = @venue.rooms
|
||||
@rooms = (@venue && @venue.rooms.any?) ? @venue.rooms : [Room.new(name: 'No Rooms!', size: 0)]
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @schedule.destroy
|
||||
redirect_to admin_conference_schedules_path(conference_id: @conference.short_title),
|
||||
notice: 'Schedule successfully deleted.'
|
||||
else
|
||||
@rooms = [ Room.new(name: 'No Rooms!', size: 0) ]
|
||||
redirect_to admin_conference_schedules_path(conference_id: @conference.short_title),
|
||||
error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}."
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, @program.events.new
|
||||
event = Event.where(guid: params[:event]).first
|
||||
error_message = nil
|
||||
if event.nil?
|
||||
error_message = "Could not find event GUID: #{params[:event]}"
|
||||
end
|
||||
|
||||
if params[:date] == 'none'
|
||||
event.start_time = nil
|
||||
event.room = nil
|
||||
event.save!
|
||||
render json: { 'status' => 'ok' }
|
||||
return
|
||||
end
|
||||
room = Room.where(guid: room_params).first
|
||||
if room.nil?
|
||||
error_message = "Could not find room GUID: #{params[:room]}"
|
||||
end
|
||||
|
||||
unless error_message.nil?
|
||||
render json: { 'status' => 'error', 'message' => error_message }, status: 500
|
||||
return
|
||||
end
|
||||
|
||||
event.room = room
|
||||
time = "#{params[:date]} #{params[:time]}"
|
||||
|
||||
Rails.logger.debug("Loading #{time}")
|
||||
# FIXME: Same here as in events_controller.rb. Event timezone should be applied
|
||||
# only on output
|
||||
# zone = ActiveSupport::TimeZone::new(@conference.timezone)
|
||||
# start_time = DateTime.strptime(time + zone.formatted_offset, "%Y-%m-%d %k:%M %Z")
|
||||
start_time = DateTime.strptime(time, '%Y-%m-%d %k:%M')
|
||||
event.start_time = start_time
|
||||
event.save!
|
||||
render json: { 'status' => 'ok' }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def event_params
|
||||
params.require(:event).permit(:guid)
|
||||
end
|
||||
|
||||
def room_params
|
||||
params.require(:room)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Api
|
|||
respond_to :json
|
||||
|
||||
def index
|
||||
events = Event.includes(:track, :room, :event_type, event_users: :user)
|
||||
events = Event.includes(:track, :event_type, event_users: :user)
|
||||
|
||||
if @conference
|
||||
events = events.where(program: @conference.program)
|
||||
|
|
|
|||
|
|
@ -11,38 +11,6 @@ class ConferenceController < ApplicationController
|
|||
|
||||
def show; end
|
||||
|
||||
def schedule
|
||||
@rooms = @conference.venue.rooms if @conference.venue
|
||||
unless @conference.program.events.scheduled.any?
|
||||
redirect_to events_conference_path(@conference.short_title)
|
||||
end
|
||||
|
||||
@events = @conference.program.events
|
||||
@events_xml = @events.scheduled.order(start_time: :asc).group_by{ |event| event.start_time.to_date }
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
@step_minutes = EventType::LENGTH_STEP.minutes
|
||||
@conf_start = 9
|
||||
conf_end = 20
|
||||
@conf_period = conf_end - @conf_start
|
||||
|
||||
# the schedule takes you to today if it is a date of the schedule
|
||||
@current_day = @conference.current_conference_day
|
||||
@day = @current_day.present? ? @current_day : @dates.first
|
||||
return unless @current_day
|
||||
# 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, conf_end)
|
||||
end
|
||||
|
||||
def events
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
|
||||
@scheduled_events = @conference.program.events.scheduled
|
||||
@unscheduled_events = @conference.program.events.unscheduled
|
||||
|
||||
day = @conference.current_conference_day
|
||||
@tag = day.strftime('%Y-%m-%d') if day
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def respond_to_options
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class ProposalController < ApplicationController
|
|||
def show
|
||||
# FIXME: We should show more than the first speaker
|
||||
@speaker = @event.speakers.first || @event.submitter
|
||||
@event_schedule = @event.event_schedules.find_by(schedule_id: @program.selected_schedule_id)
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
|
|||
52
app/controllers/schedules_controller.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
class SchedulesController < ApplicationController
|
||||
protect_from_forgery with: :null_session
|
||||
before_action :respond_to_options
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
load_resource :program, through: :conference, singleton: true, except: :index
|
||||
|
||||
def show
|
||||
@rooms = @conference.venue.rooms if @conference.venue
|
||||
schedules = @program.selected_event_schedules
|
||||
unless schedules
|
||||
redirect_to events_conference_schedule_path(@conference.short_title)
|
||||
end
|
||||
|
||||
@events_xml = schedules.map(&:event).group_by{ |event| event.time.to_date } if schedules
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
@step_minutes = EventType::LENGTH_STEP.minutes
|
||||
@conf_start = 9
|
||||
conf_end = 20
|
||||
@conf_period = conf_end - @conf_start
|
||||
|
||||
# the schedule takes you to today if it is a date of the schedule
|
||||
@current_day = @conference.current_conference_day
|
||||
@day = @current_day.present? ? @current_day : @dates.first
|
||||
return unless @current_day
|
||||
# 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, conf_end)
|
||||
end
|
||||
|
||||
def events
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
|
||||
@events_schedules = @program.selected_event_schedules
|
||||
@events_schedules = [] unless @events_schedules
|
||||
|
||||
@unscheduled_events = if @program.selected_schedule
|
||||
@program.events.confirmed - @program.selected_schedule.events
|
||||
else
|
||||
@program.events.confirmed
|
||||
end
|
||||
|
||||
day = @conference.current_conference_day
|
||||
@tag = day.strftime('%Y-%m-%d') if day
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def respond_to_options
|
||||
respond_to do |format|
|
||||
format.html { head :ok }
|
||||
end if request.options?
|
||||
end
|
||||
end
|
||||
|
|
@ -366,4 +366,8 @@ module ApplicationHelper
|
|||
end
|
||||
item_class
|
||||
end
|
||||
|
||||
def selected_scheduled?(schedule)
|
||||
(schedule == @selected_schedule) ? 'Yes' : 'No'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ class Ability
|
|||
can :manage, Vposition, conference_id: conf_ids_for_organizer
|
||||
can :manage, Vday, conference_id: conf_ids_for_organizer
|
||||
can :manage, Program, conference_id: conf_ids_for_organizer
|
||||
can :manage, Schedule, program: { conference_id: conf_ids_for_organizer }
|
||||
can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organizer } }
|
||||
can :manage, Cfp, program: { conference_id: conf_ids_for_organizer}
|
||||
can :manage, Event, program: { conference_id: conf_ids_for_organizer}
|
||||
can :manage, EventType, program: { conference_id: conf_ids_for_organizer}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class EmailSettings < ActiveRecord::Base
|
|||
'conference_splash_link' => Rails.application.routes.url_helpers.conference_url(
|
||||
conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000')),
|
||||
|
||||
'schedule_link' => Rails.application.routes.url_helpers.schedule_conference_url(
|
||||
'schedule_link' => Rails.application.routes.url_helpers.conference_schedule_url(
|
||||
conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000'))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ class Event < ActiveRecord::Base
|
|||
|
||||
has_many :events_registrations
|
||||
has_many :registrations, through: :events_registrations
|
||||
has_many :event_schedules, dependent: :destroy
|
||||
|
||||
belongs_to :track
|
||||
belongs_to :room
|
||||
belongs_to :difficulty_level
|
||||
belongs_to :program
|
||||
|
||||
|
|
@ -71,11 +71,11 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
|
||||
##
|
||||
# Checkes if the event has a start_time and a room
|
||||
# Checkes if the event has a start_time and a room for the selected schedule if there is any
|
||||
# ====Returns
|
||||
# * +true+ or +false+
|
||||
def scheduled?
|
||||
room.present? && start_time.present?
|
||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).present?
|
||||
end
|
||||
|
||||
def registration_possible?
|
||||
|
|
@ -129,16 +129,6 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def as_json(options)
|
||||
json = super(options)
|
||||
|
||||
json[:room_guid] = room.try(:guid)
|
||||
json[:track_color] = track.try(:color) || '#FFFFFF'
|
||||
json[:length] = event_type.try(:length) || EventType::LENGTH_STEP
|
||||
|
||||
json
|
||||
end
|
||||
|
||||
def transition_possible?(transition)
|
||||
self.class.state_machine.events_for(current_state).include?(transition)
|
||||
end
|
||||
|
|
@ -242,17 +232,19 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
|
||||
##
|
||||
# Returns end of the event
|
||||
# Returns the room in which the event is scheduled
|
||||
#
|
||||
def end_time
|
||||
self.start_time + self.event_type.length.minutes
|
||||
def room
|
||||
# We use try(:selected_schedule_id) because this function is used for
|
||||
# validations so program could not be present there
|
||||
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns events that are scheduled in the same room and start_time as event
|
||||
# Returns the start time at which this event is scheduled
|
||||
#
|
||||
def intersecting_events
|
||||
room.events.where(start_time: start_time).where.not(id: id)
|
||||
def time
|
||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
30
app/models/event_schedule.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
class EventSchedule < ActiveRecord::Base
|
||||
belongs_to :schedule
|
||||
belongs_to :event
|
||||
belongs_to :room
|
||||
|
||||
validates :schedule, presence: true
|
||||
validates :event, presence: true
|
||||
validates :room, presence: true
|
||||
validates :start_time, presence: true
|
||||
|
||||
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
|
||||
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
|
||||
scope :withdrawn, -> { joins(:event).where('state = ?', 'withdrawn') }
|
||||
|
||||
delegate :guid, to: :room, prefix: true
|
||||
|
||||
##
|
||||
# Returns end of the event
|
||||
#
|
||||
def end_time
|
||||
start_time + event.event_type.length.minutes
|
||||
end
|
||||
|
||||
##
|
||||
# Returns events that are scheduled in the same room and start_time as event
|
||||
#
|
||||
def intersecting_events
|
||||
room.event_schedules.where(start_time: start_time, schedule: schedule).where.not(id: id)
|
||||
end
|
||||
end
|
||||
|
|
@ -7,6 +7,8 @@ class Program < ActiveRecord::Base
|
|||
has_many :event_types, dependent: :destroy
|
||||
has_many :tracks, dependent: :destroy
|
||||
has_many :difficulty_levels, dependent: :destroy
|
||||
has_many :schedules, dependent: :destroy
|
||||
belongs_to :selected_schedule, class_name: 'Schedule'
|
||||
has_many :events, dependent: :destroy do
|
||||
def require_registration
|
||||
where(require_registration: true, state: :confirmed)
|
||||
|
|
@ -26,12 +28,8 @@ class Program < ActiveRecord::Base
|
|||
where(state: :confirmed)
|
||||
end
|
||||
|
||||
def scheduled
|
||||
where.not(start_time: nil).where.not(room: nil).order(start_time: :asc)
|
||||
end
|
||||
|
||||
def unscheduled
|
||||
confirmed.where('start_time IS NULL OR room_id IS NULL')
|
||||
def scheduled(schedule_id)
|
||||
joins(:event_schedules).where('event_schedules.schedule_id = ?', schedule_id)
|
||||
end
|
||||
|
||||
def highlights
|
||||
|
|
@ -59,6 +57,11 @@ class Program < ActiveRecord::Base
|
|||
before_create :create_difficulty_levels
|
||||
validate :check_languages_format
|
||||
|
||||
# Returns all event_schedules for the selected schedule ordered by start_time
|
||||
def selected_event_schedules
|
||||
selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if blind_voting is enabled and if voting period is over
|
||||
# ====Returns
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class Room < ActiveRecord::Base
|
||||
belongs_to :venue
|
||||
has_many :events, dependent: :nullify
|
||||
has_many :event_schedules, dependent: :nullify
|
||||
|
||||
before_create :generate_guid
|
||||
|
||||
|
|
|
|||
5
app/models/schedule.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class Schedule < ActiveRecord::Base
|
||||
belongs_to :program
|
||||
has_many :event_schedules, dependent: :destroy
|
||||
has_many :events, through: :event_schedules
|
||||
end
|
||||
|
|
@ -22,23 +22,23 @@ class ConferenceSerializer < ActiveModel::Serializer
|
|||
|
||||
def rooms
|
||||
if object.venue
|
||||
object.venue.rooms.includes(:events).map do |room| { id: room.id,
|
||||
size: room.size,
|
||||
events: room.events.map do |event| { guid: event.title,
|
||||
title: event.title,
|
||||
subtitle: event.subtitle,
|
||||
abstract: event.abstract,
|
||||
description: event.description,
|
||||
is_highlight: event.is_highlight,
|
||||
require_registration: event.require_registration,
|
||||
start_time: event.start_time,
|
||||
event_type_id: event.event_type.id,
|
||||
difficulty_level_id: event.difficulty_level_id,
|
||||
track_id: event.track_id,
|
||||
speaker_names: event.speaker_names
|
||||
object.venue.rooms.map do |room| { id: room.id,
|
||||
size: room.size,
|
||||
events: room.event_schedules.map do |event_schedule| { guid: event_schedule.event.title,
|
||||
title: event_schedule.event.title,
|
||||
subtitle: event_schedule.event.subtitle,
|
||||
abstract: event_schedule.event.abstract,
|
||||
description: event_schedule.event.description,
|
||||
is_highlight: event_schedule.event.is_highlight,
|
||||
require_registration: event_schedule.event.require_registration,
|
||||
start_time: event_schedule.start_time,
|
||||
event_type_id: event_schedule.event.event_type.id,
|
||||
difficulty_level_id: event_schedule.event.difficulty_level_id,
|
||||
track_id: event_schedule.event.track_id,
|
||||
speaker_names: event_schedule.event.speaker_names
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
else
|
||||
[]
|
||||
|
|
|
|||
14
app/serializers/event_schedule_serializer.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
class EventScheduleSerializer < ActiveModel::Serializer
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
attributes :date, :room
|
||||
|
||||
def date
|
||||
t = object.start_time
|
||||
t.blank? ? '' : %( #{I18n.l t, format: :short}#{t.formatted_offset(false)} )
|
||||
end
|
||||
|
||||
def room
|
||||
object.room.guid
|
||||
end
|
||||
end
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
class EventSerializer < ActiveModel::Serializer
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
attributes :guid, :title, :length, :date, :language, :abstract, :speaker_ids, :type, :room, :track
|
||||
attributes :guid, :title, :length, :scheduled_date, :language, :abstract, :speaker_ids, :type, :room, :track
|
||||
|
||||
def date
|
||||
t = object.start_time
|
||||
t.blank? ? '' : %{ #{I18n.l t, format: :short}#{t.formatted_offset(false)} }
|
||||
def scheduled_date
|
||||
t = object.time
|
||||
t.blank? ? '' : %( #{I18n.l t, format: :short}#{t.formatted_offset(false)} )
|
||||
end
|
||||
|
||||
def speaker_ids
|
||||
|
|
@ -34,7 +34,6 @@ class EventSerializer < ActiveModel::Serializer
|
|||
end
|
||||
end
|
||||
|
||||
# FIXME: duplicated logic from Event#as_json
|
||||
def length
|
||||
object.event_type.try(:length) || EventType::LENGTH_STEP
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
%h1 Commercials
|
||||
%p.text-muted
|
||||
Conference commercials will be displayed on the events in the
|
||||
= link_to "schedule,", schedule_conference_path(@conference.short_title)
|
||||
= link_to "schedule,", conference_schedule_path(@conference.short_title)
|
||||
if the event speaker didn't add an event commercial.
|
||||
- if can? :create, @conference.commercials.new
|
||||
.row
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@
|
|||
%b Room
|
||||
%td
|
||||
= @event.room.name
|
||||
- unless @event.start_time.nil?
|
||||
- unless @event.time.nil?
|
||||
%tr
|
||||
%td
|
||||
%b Scheduled time
|
||||
%td
|
||||
= @event.start_time
|
||||
= @event.time
|
||||
%tr
|
||||
%td
|
||||
%b Submitter
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
.schedule-time-column
|
||||
.schedule-time-column-header
|
||||
= Time
|
||||
- (9..18).each do |hour|
|
||||
.schedule-time-slot
|
||||
= "#{hour}:00"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:15"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:30"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:45"
|
||||
|
||||
- @rooms.each do |room|
|
||||
.schedule-room-column{:id => "schedule-room-#{room.guid}", "room-guid" => room.guid}
|
||||
.schedule-room-column-header
|
||||
= room.name
|
||||
= "(#{room.size} people)"
|
||||
- (9..18).each do |hour|
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-0", "room-guid" => room.guid, "hour" => "#{hour}:00"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-15", "room-guid" => room.guid, "hour" => "#{hour}:15"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-30", "room-guid" => room.guid, "hour" => "#{hour}:30"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-45", "room-guid" => room.guid, "hour" => "#{hour}:45"}
|
||||
- date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date }
|
||||
.row
|
||||
- @rooms.each do |room|
|
||||
.col-md-2.col-xs-6
|
||||
.room-name
|
||||
- room_date_event_schedules = date_event_schedules.select{ |e| e.room == room }
|
||||
= room.name
|
||||
- (9*4..18*4).each do |slot|
|
||||
- hour = slot / 4
|
||||
- minutes = (15 * (slot % 4) == 0) ? '00' : 15 * (slot % 4)
|
||||
- time = "#{hour}:#{minutes}"
|
||||
.schedule-room-slot{ id: "schedule-room-#{room.guid}-#{hour}-#{minutes}", |
|
||||
room_id: room.id, |
|
||||
hour: time, |
|
||||
date: date}
|
||||
.div
|
||||
= time
|
||||
- event_schedules = room_date_event_schedules.select{ |e| (e.start_time.hour.to_s + e.start_time.strftime(':%M')).eql? time }
|
||||
- if event_schedules.any?
|
||||
- event_schedule = event_schedules.first
|
||||
= render partial: 'event', locals: { event: event_schedule.event, event_schedule_id: event_schedule.id}
|
||||
|
|
|
|||
14
app/views/admin/schedules/_event.html.haml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
- cells_length = event.event_type.length / EventType::LENGTH_STEP
|
||||
/ this height fits the room cells
|
||||
- height = (cells_length * 58) - 23
|
||||
/ subtracting the padding before calculate the number of lines
|
||||
- lines = (height - 7) / 23
|
||||
- color = event.track.try(:color).present? ? event.track.try(:color) : 'FFFFFF'
|
||||
.schedule-event{ style: "height: #{height}px; background-color: #{color}; color: #{contrast_color(color)}", |
|
||||
id: "event-#{event.id}", |
|
||||
event_id: event.id, |
|
||||
length: cells_length, |
|
||||
event_schedule_id: event_schedule_id }
|
||||
.schedule-event-text{ style: "-webkit-line-clamp: #{lines}; height: #{lines * 23}px;"}
|
||||
%span.schedule-event-delete-button{ onclick: "Schedule.remove(\'event-#{event.id}\');" } X
|
||||
= event.title
|
||||
32
app/views/admin/schedules/index.html.haml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.row
|
||||
.col-md-12
|
||||
.page-header
|
||||
%h1 Schedules
|
||||
%p.text-muted
|
||||
The schedules for your conference
|
||||
.row
|
||||
.col-md-12
|
||||
%table.table.table-hover#event_types
|
||||
%thead
|
||||
%th Schedule
|
||||
%th Selected
|
||||
%th Actions
|
||||
%tbody
|
||||
- @schedules.each do |schedule|
|
||||
%tr
|
||||
%td
|
||||
Schedule
|
||||
= schedule.id
|
||||
%td
|
||||
= selected_scheduled?(schedule)
|
||||
%td
|
||||
.btn-group{role: "group"}
|
||||
= link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule.id),
|
||||
method: :get, class: 'btn btn-primary'
|
||||
= link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule.id),
|
||||
method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" }
|
||||
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title),
|
||||
method: :post, class: 'btn btn-primary'
|
||||
|
|
@ -1,48 +1,38 @@
|
|||
.schedule-content
|
||||
%h2
|
||||
= "Schedule for #{@conference.title}"
|
||||
#unscheduled.unscheduled
|
||||
.unscheduled-header
|
||||
Unscheduled Events
|
||||
#schedule.schedule
|
||||
.schedule-dates-header
|
||||
%ul#date-tabs
|
||||
- @dates.each do |date|
|
||||
%li.date-selector
|
||||
= link_to "#{date}", "#", id: "#{date}-selector", onclick: "Schedule.changeDay('#{date}')"
|
||||
.schedule-rooms-container
|
||||
= render 'day_tab'
|
||||
.unobtrusive-flash-container
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
.page-header
|
||||
%h1 Schedule
|
||||
%p.text-muted
|
||||
Create the schedules for the conference
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
Selected schedule
|
||||
= check_box_tag @conference.short_title, @schedule.id, (@schedule.id == @selected_schedule.try(:id)),
|
||||
method: :patch, url: (admin_conference_program_path(@conference.short_title) + '?[program][selected_schedule_id]='),
|
||||
class: 'switch-checkbox-schedule', data: { size: 'small',
|
||||
off_color: 'warning',
|
||||
on_text: 'Yes',
|
||||
off_text: 'No' }
|
||||
.h4
|
||||
Unscheduled events
|
||||
.unscheduled-events
|
||||
- @unscheduled_events.each do |e|
|
||||
= render partial: 'event', locals: { event: e, event_schedule_id: nil }
|
||||
.col-md-10
|
||||
%ul.nav.nav-tabs
|
||||
- @dates.each do |date|
|
||||
%li{ class: "#{ (@dates.first == date) ? 'active' : '' }"}
|
||||
%a{ href: "##{date}" }
|
||||
= date
|
||||
.tab-content
|
||||
- @dates.each do |date|
|
||||
.tab-pane{ class: "#{ (@dates.first == date) ? 'active' : '' }", id: "#{date}" }
|
||||
= render partial: 'day_tab', locals: { date: date }
|
||||
|
||||
:javascript
|
||||
$(document).ready( function() {
|
||||
//Schedule.loadDaysAndTracks("#{@conference.short_title}");
|
||||
var conference = "#{@conference.short_title}"
|
||||
Schedule.loadEvents("#{@conference.short_title}", "#{@dates.first}");
|
||||
$('.schedule-room-slot').droppable({
|
||||
accept: '.schedule-event',
|
||||
tolerance: "pointer",
|
||||
drop: function(event, ui) {
|
||||
$(ui.draggable).appendTo(this);
|
||||
var myId = $(ui.draggable).attr("guid");
|
||||
var myRoom = $(this).attr("room-guid")
|
||||
var myDate = $(this).attr("date");
|
||||
var myTime = $(this).attr("hour");
|
||||
var length = $(ui.draggable).attr("length");
|
||||
$(ui.draggable).css("left", 0);
|
||||
$(ui.draggable).css("top", 0);
|
||||
$(this).css("background-color", "#ffffff");
|
||||
|
||||
// 15 minute slots on the schedule are 30px,
|
||||
// thus the magic multiplier here
|
||||
$(ui.draggable).height(length * 2 - 7);
|
||||
$(ui.draggable).width($(this).width() - 10);
|
||||
Schedule.save(conference, myId, myRoom, myDate, myTime);
|
||||
},
|
||||
over: function(event, ui) {
|
||||
$(this).css("background-color", "#009ED8");
|
||||
},
|
||||
out: function(event, ui) {
|
||||
$(this).css("background-color", "#ffffff");
|
||||
}
|
||||
});
|
||||
});
|
||||
Schedule.initialize("#{admin_conference_event_schedules_path(@conference)}", "#{@schedule.id}");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,5 +27,4 @@
|
|||
%td
|
||||
= event.state
|
||||
%td
|
||||
= event.start_time
|
||||
|
||||
= event.time
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
- if conference.splashpage && conference.splashpage.public
|
||||
= link_to "View Conference", conference_path(conference.short_title), :class =>"btn btn-default"
|
||||
- if conference.program and conference.program.schedule_public
|
||||
= link_to "Schedule", schedule_conference_path(conference.short_title), :class =>"btn btn-default"
|
||||
= link_to "Schedule", conference_schedule_path(conference.short_title), :class =>"btn btn-default"
|
||||
- if conference.registration_open?
|
||||
- if conference.user_registered?(current_user)
|
||||
= link_to "My Registration", conference_conference_registration_path(conference.short_title), :class =>"btn btn-default"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
.row
|
||||
.col-md-12
|
||||
%p.cta-button.text-center
|
||||
= link_to(schedule_conference_path(@conference.short_title), class: 'btn btn-default btn-lg') do
|
||||
= link_to(conference_schedule_path(@conference.short_title), class: 'btn btn-default btn-lg') do
|
||||
Full Schedule
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
.text-muted
|
||||
= registered_text(event)
|
||||
- if event.scheduled?
|
||||
(Scheduled on: #{event.start_time.to_date})
|
||||
(Scheduled on: #{event.time.to_date})
|
||||
%br
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@
|
|||
- if can? :update, @conference.program.difficulty_levels.build, conference_id: @conference.id
|
||||
%li{:class=> active_nav_li(admin_conference_program_difficulty_levels_path(@conference.short_title))}
|
||||
= link_to 'Difficulty Levels', admin_conference_program_difficulty_levels_path(@conference.short_title)
|
||||
- if can? :update, @conference.program.events.build
|
||||
%li{class: active_nav_li(admin_conference_schedule_path(@conference.short_title))}
|
||||
= link_to 'Schedule', admin_conference_schedule_path(@conference.short_title), target: '_blank'
|
||||
- if can? :update, @conference.program.schedules.build
|
||||
%li{class: active_nav_li(admin_conference_schedules_path(@conference.short_title))}
|
||||
= link_to 'Schedules', admin_conference_schedules_path(@conference.short_title)
|
||||
|
||||
- if can? :update, Registration.new(conference_id: @conference.id)
|
||||
%li{:class=> active_nav_li(admin_conference_registrations_path(@conference.short_title))}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
!!!
|
||||
%html
|
||||
%head
|
||||
%meta{:charset => "utf-8"}
|
||||
%meta{:name => "viewport", :content => "width=device-width, initial-scale=1, maximum-scale=1"}
|
||||
%title= content_for?(:title) ? yield(:title) : (ENV['OSEM_NAME'] || 'OSEM')
|
||||
%meta{:content => "", :name => "description"}
|
||||
%meta{:content => "", :name => "author"}
|
||||
= stylesheet_link_tag "/stylesheets/schedule/jquery-ui-1.9.2.custom.min"
|
||||
= stylesheet_link_tag "/stylesheets/schedule/schedule"
|
||||
|
||||
= javascript_include_tag "/javascripts/schedule/jquery-1.8.3"
|
||||
= javascript_include_tag "/javascripts/schedule/jquery-ui-1.9.2.custom.min"
|
||||
= javascript_include_tag "/javascripts/schedule/date.format"
|
||||
= javascript_include_tag "/javascripts/schedule/schedule"
|
||||
= csrf_meta_tags
|
||||
= yield(:head)
|
||||
%body
|
||||
.content
|
||||
= yield
|
||||
|
|
@ -13,11 +13,11 @@
|
|||
- if can? :edit, @event
|
||||
= link_to "Edit", edit_conference_program_proposal_path(@conference.short_title, @event), :class => "btn btn-mini btn-primary"
|
||||
- if can? :schedule, @conference
|
||||
= link_to "Schedule", schedule_conference_path(@conference.short_title), :class =>"btn btn-success"
|
||||
= link_to "Schedule", conference_schedule_path(@conference.short_title), :class =>"btn btn-success"
|
||||
|
||||
- if @event.state == 'canceled' || @event.state == 'withdrawn'
|
||||
%span.label.label-danger CANCELED
|
||||
- elsif @event.state == 'confirmed' && (!@event.intersecting_events.canceled.empty? || !@event.intersecting_events.withdrawn.empty?)
|
||||
- elsif @event.state == 'confirmed' && @event_schedule.present? && (!@event_schedule.intersecting_events.canceled.empty? || !@event_schedule.intersecting_events.withdrawn.empty?)
|
||||
%span.label.label-info REPLACEMENT
|
||||
|
||||
.row
|
||||
|
|
@ -40,15 +40,16 @@
|
|||
.col-md-9
|
||||
.row
|
||||
.col-md-12
|
||||
.lead
|
||||
- if @event.state == 'confirmed' && !@event.intersecting_events.withdrawn.empty?
|
||||
= "Please note that this talk replaces"
|
||||
= link_to @event.intersecting_events.withdrawn.first.title,
|
||||
conference_program_proposal_path(@conference.short_title, @event.intersecting_events.withdrawn.first.id)
|
||||
- elsif @event.state == 'confirmed' && !@event.intersecting_events.canceled.empty?
|
||||
= "Please note that this talk replaces"
|
||||
= link_to @event.intersecting_events.canceled.first.title,
|
||||
conference_program_proposal_path(@conference.short_title, @event.intersecting_events.canceled.first.id)
|
||||
-if @event_schedule.present?
|
||||
.lead
|
||||
- if @event.state == 'confirmed' && !@event_schedule.intersecting_events.withdrawn.empty?
|
||||
= "Please note that this talk replaces"
|
||||
= link_to @event_schedule.intersecting_events.withdrawn.first.event.title,
|
||||
conference_program_proposal_path(@conference.short_title, @event_schedule.intersecting_events.withdrawn.first.event.id)
|
||||
- elsif @event.state == 'confirmed' && !@event_schedule.intersecting_events.canceled.empty?
|
||||
= "Please note that this talk replaces"
|
||||
= link_to @event_schedule.intersecting_events.canceled.first.title,
|
||||
conference_program_proposal_path(@conference.short_title, @event_schedule.intersecting_events.canceled.first.event.id)
|
||||
|
||||
- if @event.commercials.empty?
|
||||
%h5.text-warning
|
||||
|
|
@ -67,7 +68,7 @@
|
|||
%dl#proposal-info
|
||||
.col-md-12
|
||||
%dt Date:
|
||||
%dd= @event.start_time.strftime("%Y %B %e %H:%M") if @event.start_time
|
||||
%dd= @event_schedule.start_time.strftime("%Y %B %e %H:%M") if @event_schedule
|
||||
.col-md-12
|
||||
%dt Duration:
|
||||
%dd= show_time(@event.event_type.length)
|
||||
|
|
|
|||
|
|
@ -27,22 +27,21 @@
|
|||
%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.name
|
||||
- events = room.events{ |e| e.start_time >= start_time and e.start_time < (start_time + number_columns.hour)}
|
||||
- event_schedules = room.event_schedules.select{ |e| (e.schedule_id == @conference.program.selected_schedule.id) && (e.start_time >= start_time) && (e.start_time < (start_time + number_columns.hour)) }
|
||||
- (1..intervals).each do |i|
|
||||
- if span > 1
|
||||
- span -= 1
|
||||
- else
|
||||
- event = events.find{|e| e.start_time <= start_room_time and e.end_time > start_room_time}
|
||||
- event_schedule = event_schedules.find{ |e| e.start_time <= start_room_time and e.end_time > start_room_time }
|
||||
- if event_schedule && (event_schedule.event.state == 'canceled' || event_schedule.event.state == 'withdrawn') && !event_schedule.intersecting_events.confirmed.empty?
|
||||
- replacement_event = event_schedule.intersecting_events.confirmed.first
|
||||
- event_schedule = (replacement_event.start_time <= start_room_time && replacement_event.end_time > start_room_time) ? replacement_event : nil
|
||||
|
||||
- if event && (event.state == 'canceled' || event.state == 'withdrawn') && !event.intersecting_events.confirmed.empty?
|
||||
- replacement_event = event.intersecting_events.confirmed.first
|
||||
- event = (replacement_event.start_time <= start_room_time && replacement_event.end_time > start_room_time) ? replacement_event : nil
|
||||
|
||||
- if event
|
||||
- if event_schedule
|
||||
/ There is an event, calculate the span and show it
|
||||
- event_span = (event.end_time.to_i - start_room_time.to_i) / 60 / EventType::LENGTH_STEP
|
||||
- event_span = (event_schedule.end_time.to_i - start_room_time.to_i) / 60 / EventType::LENGTH_STEP
|
||||
- span = ((event_span + i - 1 ) > intervals ? intervals + 1 - i : event_span)
|
||||
= render partial: 'schedule_item', locals: {event: event, span: span, width: width}
|
||||
= render partial: 'schedule_item', locals: {event: event_schedule.event, event_schedule: event_schedule, span: span, width: width}
|
||||
- else
|
||||
/ if span equals 1 show an empty td
|
||||
%td.no-padding{ width: "#{ width }%"}
|
||||
|
|
@ -14,17 +14,17 @@
|
|||
%p
|
||||
= truncate(event.abstract, :length => 400)
|
||||
= link_to 'more', conference_program_proposal_path(@conference.short_title, event.id) if event.abstract.length > 400
|
||||
- if event.scheduled?
|
||||
- if event_schedule.present?
|
||||
%span.track
|
||||
%span.fa.fa-clock-o
|
||||
%span.label{ style: "background-color: grey" }
|
||||
= event.start_time.strftime('%H:%M')
|
||||
= event_schedule.start_time.strftime('%H:%M')
|
||||
\-
|
||||
= event.end_time.strftime('%H:%M')
|
||||
= event_schedule.end_time.strftime('%H:%M')
|
||||
%span.track
|
||||
%span.fa.fa-map-marker
|
||||
%span.label{ style: "background-color: grey" }
|
||||
= event.room.name
|
||||
= event_schedule.room.name
|
||||
- if event.track
|
||||
%span.track
|
||||
%span.fa.fa-road
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
$("#link-#{event.id}").click(function(e) {
|
||||
var url = "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}";
|
||||
|
||||
|
||||
if(e.ctrlKey)
|
||||
window.open(url,'_blank');
|
||||
else
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
- if event.state == 'canceled' || event.state == 'withdrawn'
|
||||
%span.label.label-danger.schedule-label CANCELED
|
||||
- elsif event.state == 'confirmed' && (!event.intersecting_events.canceled.empty? || !event.intersecting_events.withdrawn.empty?)
|
||||
- elsif event.state == 'confirmed' && (!event_schedule.intersecting_events.canceled.empty? || !event_schedule.intersecting_events.withdrawn.empty?)
|
||||
%span.label.label-info.schedule-label REPLACEMENT
|
||||
|
||||
= event.title
|
||||
|
|
@ -2,6 +2,6 @@
|
|||
/ Nav tabs
|
||||
%ul.nav.nav-tabs{ role: "tablist" }
|
||||
%li{ class: "schedule #{ 'active' if active == 'schedule' }", role: "presentation" }
|
||||
= link_to('Schedule', schedule_conference_path(@conference.short_title))
|
||||
= link_to('Schedule', conference_schedule_path(@conference.short_title))
|
||||
%li{ class: "program #{ 'active' if active == 'program' }", role: "presentation" }
|
||||
= link_to('All events', events_conference_path(@conference.short_title))
|
||||
= link_to('All events', events_conference_schedule_path(@conference.short_title))
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
.container#program
|
||||
-if @scheduled_events.any?
|
||||
-if @events_schedules.any?
|
||||
= render partial: 'schedule_tabs', locals: { active: 'program' }
|
||||
|
||||
%h1.text-center
|
||||
|
|
@ -22,24 +22,24 @@
|
|||
/ scheduled events
|
||||
- date = nil
|
||||
- time = nil
|
||||
- @scheduled_events.each do |event|
|
||||
- unless event.start_time.strftime('%Y-%m-%d').eql?(date)
|
||||
- @events_schedules.each do |event_schedule|
|
||||
- unless event_schedule.start_time.strftime('%Y-%m-%d').eql?(date)
|
||||
.col-xs-12.col-md-12
|
||||
.date-content
|
||||
%span{ class: 'date-title', id: "#{ event.start_time.strftime('%Y-%m-%d') }" }
|
||||
= date = event.start_time.strftime('%Y-%m-%d')
|
||||
%span{ class: 'date-title', id: "#{ event_schedule.start_time.strftime('%Y-%m-%d') }" }
|
||||
= date = event_schedule.start_time.strftime('%Y-%m-%d')
|
||||
%a{ title: "Go up", class: "pull-right", href: "#program" }
|
||||
%i{ class: "fa fa-angle-double-up fa-lg", 'aria-hidden' => true }
|
||||
- unless event.start_time.strftime('%H:%M').eql?(time)
|
||||
- unless event_schedule.start_time.strftime('%H:%M').eql?(time)
|
||||
.col-xs-12.col-md-1
|
||||
.start-time
|
||||
= time = event.start_time.strftime('%H:%M')
|
||||
= time = event_schedule.start_time.strftime('%H:%M')
|
||||
.col-xs-12.col-md-11
|
||||
.new-time-event
|
||||
= render partial: 'event', locals: {event: event}
|
||||
= render partial: 'event', locals: { event: event_schedule.event, event_schedule: event_schedule }
|
||||
- else
|
||||
.col-xs-12.col-md-11.col-md-offset-1
|
||||
= render partial: 'event', locals: {event: event}
|
||||
= render partial: 'event', locals: { event: event_schedule.event, event_schedule: event_schedule }
|
||||
|
||||
/ confirmed events that are not scheduled
|
||||
- if @unscheduled_events.any?
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
- @unscheduled_events.each do |event|
|
||||
.col-xs-12.col-md-12
|
||||
.unscheduled-event
|
||||
= render partial: 'event', locals: {event: event}
|
||||
= render partial: 'event', locals: { event: event, event_schedule: nil }
|
||||
|
||||
:javascript
|
||||
$('.program-selector').on('click', function(e) {
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
%room{ name: room.name }
|
||||
- events_in_rooms[room].each do |event|
|
||||
%event{ guid: event.guid, id: event.id }
|
||||
%date= event.start_time.iso8601
|
||||
%start= event.start_time.strftime('%H:%M')
|
||||
%date= event.time.iso8601
|
||||
%start= event.time.strftime('%H:%M')
|
||||
%duration= length_timestamp(event.event_type.length)
|
||||
%room= event.room.name
|
||||
%type= event.event_type.name
|
||||
|
|
@ -22,7 +22,8 @@ Osem::Application.routes.draw do
|
|||
resources :comments, only: [:index]
|
||||
resources :conference do
|
||||
resource :contact, except: [:index, :new, :create, :show, :destroy]
|
||||
resource :schedule, only: [:show, :update]
|
||||
resources :schedules, only: [:index, :create, :show, :update, :destroy]
|
||||
resources :event_schedules, only: [:create, :update, :destroy]
|
||||
get 'commercials/render_commercial' => 'commercials#render_commercial'
|
||||
resources :commercials, only: [:index, :create, :update, :destroy]
|
||||
get '/volunteers_list' => 'volunteers#show'
|
||||
|
|
@ -112,10 +113,10 @@ Osem::Application.routes.draw do
|
|||
resources :tickets, only: [:index]
|
||||
resources :ticket_purchases, only: [:create, :destroy]
|
||||
resource :subscriptions, only: [:create, :destroy]
|
||||
|
||||
member do
|
||||
get :schedule
|
||||
get :events
|
||||
resource :schedule, only: [:show] do
|
||||
member do
|
||||
get :events
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
9
db/migrate/20160704091928_create_schedules.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class CreateSchedules < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :schedules do |t|
|
||||
t.belongs_to :program, index: true
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_reference :programs, :selected_schedule, index: true
|
||||
end
|
||||
end
|
||||
11
db/migrate/20160704092023_create_event_schedules.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class CreateEventSchedules < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :event_schedules do |t|
|
||||
t.belongs_to :event, index: true
|
||||
t.belongs_to :schedule, index: true
|
||||
t.belongs_to :room, index: true
|
||||
t.datetime :start_time
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
34
db/schema.rb
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160624151257) do
|
||||
ActiveRecord::Schema.define(version: 20160704092023) do
|
||||
|
||||
create_table "ahoy_events", force: :cascade do |t|
|
||||
t.uuid "visit_id", limit: 16
|
||||
|
|
@ -176,6 +176,19 @@ ActiveRecord::Schema.define(version: 20160624151257) do
|
|||
t.text "cfp_dates_updated_body"
|
||||
end
|
||||
|
||||
create_table "event_schedules", force: :cascade do |t|
|
||||
t.integer "event_id"
|
||||
t.integer "schedule_id"
|
||||
t.integer "room_id"
|
||||
t.datetime "start_time"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "event_schedules", ["event_id"], name: "index_event_schedules_on_event_id"
|
||||
add_index "event_schedules", ["room_id"], name: "index_event_schedules_on_room_id"
|
||||
add_index "event_schedules", ["schedule_id"], name: "index_event_schedules_on_schedule_id"
|
||||
|
||||
create_table "event_types", force: :cascade do |t|
|
||||
t.string "title", null: false
|
||||
t.integer "length", default: 30
|
||||
|
|
@ -252,17 +265,20 @@ ActiveRecord::Schema.define(version: 20160624151257) do
|
|||
|
||||
create_table "programs", force: :cascade do |t|
|
||||
t.integer "conference_id"
|
||||
t.integer "rating", default: 0
|
||||
t.boolean "schedule_public", default: false
|
||||
t.boolean "schedule_fluid", default: false
|
||||
t.integer "rating", default: 0
|
||||
t.boolean "schedule_public", default: false
|
||||
t.boolean "schedule_fluid", default: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "languages"
|
||||
t.boolean "blind_voting", default: false
|
||||
t.boolean "blind_voting", default: false
|
||||
t.datetime "voting_start_date"
|
||||
t.datetime "voting_end_date"
|
||||
t.integer "selected_schedule_id"
|
||||
end
|
||||
|
||||
add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id"
|
||||
|
||||
create_table "qanswers", force: :cascade do |t|
|
||||
t.integer "question_id"
|
||||
t.integer "answer_id"
|
||||
|
|
@ -335,6 +351,14 @@ ActiveRecord::Schema.define(version: 20160624151257) do
|
|||
t.integer "venue_id", null: false
|
||||
end
|
||||
|
||||
create_table "schedules", force: :cascade do |t|
|
||||
t.integer "program_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "schedules", ["program_id"], name: "index_schedules_on_program_id"
|
||||
|
||||
create_table "splashpages", force: :cascade do |t|
|
||||
t.integer "conference_id"
|
||||
t.boolean "public"
|
||||
|
|
|
|||
24
lib/tasks/several_schedules.rake
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace :data do
|
||||
desc 'Move the start_time and room attributes from Event to EventSchedule'
|
||||
|
||||
task move_events_attributes: :environment do
|
||||
Program.all.each do |program|
|
||||
schedule = Schedule.create(program: program)
|
||||
program.selected_schedule = schedule
|
||||
program.save
|
||||
program.events.each do |event|
|
||||
unless event.start_time.nil? && event.room_id.nil?
|
||||
# we can not use .room as this relation has been removed
|
||||
EventSchedule.create(event: event,
|
||||
schedule: schedule,
|
||||
start_time: event.start_time,
|
||||
room_id: event.room_id)
|
||||
event.start_time = nil
|
||||
event.room_id = nil
|
||||
event.save
|
||||
end
|
||||
end
|
||||
end
|
||||
puts 'The start_time and room attributes has been moved from Event to EventSchedule'
|
||||
end
|
||||
end
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* Date Format 1.2.3
|
||||
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
|
||||
* MIT license
|
||||
*
|
||||
* Includes enhancements by Scott Trenda <scott.trenda.net>
|
||||
* and Kris Kowal <cixar.com/~kris.kowal/>
|
||||
*
|
||||
* Accepts a date, a mask, or a date and a mask.
|
||||
* Returns a formatted version of the given date.
|
||||
* The date defaults to the current date/time.
|
||||
* The mask defaults to dateFormat.masks.default.
|
||||
*/
|
||||
|
||||
var dateFormat = function () {
|
||||
var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
|
||||
timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
|
||||
timezoneClip = /[^-+\dA-Z]/g,
|
||||
pad = function (val, len) {
|
||||
val = String(val);
|
||||
len = len || 2;
|
||||
while (val.length < len) val = "0" + val;
|
||||
return val;
|
||||
};
|
||||
|
||||
// Regexes and supporting functions are cached through closure
|
||||
return function (date, mask, utc) {
|
||||
var dF = dateFormat;
|
||||
|
||||
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
|
||||
if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
|
||||
mask = date;
|
||||
date = undefined;
|
||||
}
|
||||
|
||||
// Passing date through Date applies Date.parse, if necessary
|
||||
date = date ? new Date(date) : new Date;
|
||||
if (isNaN(date)) throw SyntaxError("invalid date");
|
||||
|
||||
mask = String(dF.masks[mask] || mask || dF.masks["default"]);
|
||||
|
||||
// Allow setting the utc argument via the mask
|
||||
if (mask.slice(0, 4) == "UTC:") {
|
||||
mask = mask.slice(4);
|
||||
utc = true;
|
||||
}
|
||||
|
||||
var _ = utc ? "getUTC" : "get",
|
||||
d = date[_ + "Date"](),
|
||||
D = date[_ + "Day"](),
|
||||
m = date[_ + "Month"](),
|
||||
y = date[_ + "FullYear"](),
|
||||
H = date[_ + "Hours"](),
|
||||
M = date[_ + "Minutes"](),
|
||||
s = date[_ + "Seconds"](),
|
||||
L = date[_ + "Milliseconds"](),
|
||||
o = utc ? 0 : date.getTimezoneOffset(),
|
||||
flags = {
|
||||
d: d,
|
||||
dd: pad(d),
|
||||
ddd: dF.i18n.dayNames[D],
|
||||
dddd: dF.i18n.dayNames[D + 7],
|
||||
m: m + 1,
|
||||
mm: pad(m + 1),
|
||||
mmm: dF.i18n.monthNames[m],
|
||||
mmmm: dF.i18n.monthNames[m + 12],
|
||||
yy: String(y).slice(2),
|
||||
yyyy: y,
|
||||
h: H % 12 || 12,
|
||||
hh: pad(H % 12 || 12),
|
||||
H: H,
|
||||
HH: pad(H),
|
||||
M: M,
|
||||
MM: pad(M),
|
||||
s: s,
|
||||
ss: pad(s),
|
||||
l: pad(L, 3),
|
||||
L: pad(L > 99 ? Math.round(L / 10) : L),
|
||||
t: H < 12 ? "a" : "p",
|
||||
tt: H < 12 ? "am" : "pm",
|
||||
T: H < 12 ? "A" : "P",
|
||||
TT: H < 12 ? "AM" : "PM",
|
||||
Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
|
||||
o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
|
||||
S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
|
||||
};
|
||||
|
||||
return mask.replace(token, function ($0) {
|
||||
return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
|
||||
});
|
||||
};
|
||||
}();
|
||||
|
||||
// Some common format strings
|
||||
dateFormat.masks = {
|
||||
"default": "ddd mmm dd yyyy HH:MM:ss",
|
||||
shortDate: "m/d/yy",
|
||||
mediumDate: "mmm d, yyyy",
|
||||
longDate: "mmmm d, yyyy",
|
||||
fullDate: "dddd, mmmm d, yyyy",
|
||||
shortTime: "h:MM TT",
|
||||
mediumTime: "h:MM:ss TT",
|
||||
longTime: "h:MM:ss TT Z",
|
||||
isoDate: "yyyy-mm-dd",
|
||||
isoTime: "HH:MM:ss",
|
||||
isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
|
||||
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
|
||||
};
|
||||
|
||||
// Internationalization strings
|
||||
dateFormat.i18n = {
|
||||
dayNames: [
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||
],
|
||||
monthNames: [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
|
||||
]
|
||||
};
|
||||
|
||||
// For convenience...
|
||||
Date.prototype.format = function (mask, utc) {
|
||||
return dateFormat(this, mask, utc);
|
||||
};
|
||||
|
||||
9472
public/javascripts/schedule/jquery-1.8.3.js
vendored
|
|
@ -1,178 +0,0 @@
|
|||
Array.prototype.remove = function() {
|
||||
var what, a = arguments, L = a.length, ax;
|
||||
while (L && this.length) {
|
||||
what = a[--L];
|
||||
while ((ax = this.indexOf(what)) !== -1) {
|
||||
this.splice(ax, 1);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Date.prototype.addDays = function(days) {
|
||||
var dat = new Date(this.valueOf())
|
||||
dat.setDate(dat.getDate() + days);
|
||||
return dat;
|
||||
}
|
||||
|
||||
function getDates(startDate, stopDate) {
|
||||
var dateArray = new Array();
|
||||
var currentDate = startDate;
|
||||
while (currentDate <= stopDate) {
|
||||
dateArray.push(currentDate)
|
||||
currentDate = currentDate.addDays(1);
|
||||
}
|
||||
return dateArray;
|
||||
}
|
||||
|
||||
var scheduleDayEvents = {};
|
||||
|
||||
var Schedule = {
|
||||
loadEvents: function(conference_id, start_date) {
|
||||
var eventDates = {};
|
||||
var url = '/admin/conference/' + conference_id + '/program/events';
|
||||
var params = { start: $('#start').text(), end: $('#end').text()};
|
||||
var callback = function(data) {
|
||||
$.each(data, function(key, val) {
|
||||
Schedule.newEvent(val, conference_id);
|
||||
});
|
||||
Schedule.changeDay(start_date);
|
||||
};
|
||||
$.getJSON(url, params, callback);
|
||||
},
|
||||
newEvent: function(vars, conference_id) {
|
||||
var newEvent = $('<div>'
|
||||
+ '<div onclick="Schedule.remove(\'event-' + vars["guid"] + '\', \'' + conference_id +'\');" class="schedule-event-delete-button">X</div>'
|
||||
+ '<div>' + vars["title"] + '</div></div>');
|
||||
var date = "none";
|
||||
var hour = "12";
|
||||
var minute = "0";
|
||||
console.log(vars);
|
||||
if (vars["start_time"] != null) {
|
||||
var d = new Date(vars["start_time"]);
|
||||
date = d.getUTCFullYear() + "-"
|
||||
+ ('0' + (d.getUTCMonth() +1)).slice(-2) + '-'
|
||||
+ ('0' + d.getUTCDate()).slice(-2);
|
||||
hour = d.getUTCHours();
|
||||
minute = d.getUTCMinutes();
|
||||
console.log("date: " + d);
|
||||
}
|
||||
newEvent.addClass("schedule-event");
|
||||
newEvent.css('background-color',vars["track_color"]);
|
||||
newEvent.attr("id", "event-" + vars["guid"]);
|
||||
newEvent.attr("room", vars["room_guid"]);
|
||||
newEvent.attr("guid", vars["guid"]);
|
||||
newEvent.attr("length", vars["length"]);
|
||||
newEvent.attr("date", date);
|
||||
newEvent.attr("hour", hour);
|
||||
newEvent.attr("minute", minute);
|
||||
newEvent.draggable({
|
||||
snap: '.schedule-track-slot',
|
||||
revertDuration: 200,
|
||||
revert: function (event, ui) {
|
||||
// $(this).data("draggable").originalPosition = {
|
||||
// top: 0,
|
||||
// left: 0
|
||||
// };
|
||||
console.log(event.attr);
|
||||
return !event;
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
this._originalPosition = this._originalPosition || ui.originalPosition;
|
||||
ui.helper.animate( this._originalPosition );
|
||||
},
|
||||
start: function( event, ui ) {
|
||||
$(ui.helper).height(ui.helper.attr("length") * 2 - 7);
|
||||
|
||||
},
|
||||
opacity: 0.7,
|
||||
snapMode: "inner",
|
||||
zIndex: 2
|
||||
});
|
||||
if (date == "none" || vars["room_id"] == null) {
|
||||
$('#unscheduled').append(newEvent);
|
||||
} else {
|
||||
if (!scheduleDayEvents.hasOwnProperty(date)) {
|
||||
scheduleDayEvents[date] = new Array();
|
||||
}
|
||||
newEvent.height(newEvent.attr("length") * 2 - 7);
|
||||
newEvent.width(200 - 10);
|
||||
scheduleDayEvents[date].push(newEvent);
|
||||
}
|
||||
},
|
||||
remove: function(element, conference_id) {
|
||||
var e = $("#" + element);
|
||||
var unscheduled = $("#unscheduled");
|
||||
|
||||
var url = '/admin/conference/' + conference_id + '/schedule';
|
||||
var params = {
|
||||
event: e.attr("guid"),
|
||||
room: "none",
|
||||
date: "none",
|
||||
time: "none"
|
||||
};
|
||||
var callback = function(data) {
|
||||
console.log(data);
|
||||
e.height(10);
|
||||
e.width(unscheduled.width())
|
||||
e.appendTo(unscheduled);
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'PUT',
|
||||
data: params,
|
||||
success: callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
},
|
||||
changeDay: function(date) {
|
||||
$(".date-selector").removeClass("active");
|
||||
$(".date-selector #" + date + "-selector").parent().addClass("active");
|
||||
$(".schedule-room-slot").attr("date", date);
|
||||
// Now clear all of the attached events
|
||||
$(".schedule-rooms-container .schedule-event").remove();
|
||||
if (scheduleDayEvents.hasOwnProperty(date)) {
|
||||
var events = scheduleDayEvents[date];
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var elem = events[i];
|
||||
elem.draggable({
|
||||
grid: [200,31],
|
||||
snap: '.schedule-track-slot',
|
||||
revert: function (event, ui) {
|
||||
$(this).data("draggable").originalPosition = {
|
||||
top: 0,
|
||||
left: 0
|
||||
};
|
||||
return !event;
|
||||
},
|
||||
opacity: 0.7,
|
||||
snapMode: "inner",
|
||||
zIndex: 2
|
||||
});
|
||||
|
||||
var attachStr = "#schedule-room-" + elem.attr("room") + "-" + elem.attr("hour") + "-" + elem.attr("minute");
|
||||
$(attachStr).append(elem);
|
||||
}
|
||||
}
|
||||
},
|
||||
save: function (conference_id, event_id, room_id, date, time) {
|
||||
var url = '/admin/conference/' + conference_id + '/schedule';
|
||||
var params = {
|
||||
event: event_id,
|
||||
room: room_id,
|
||||
date: date,
|
||||
time: time
|
||||
};
|
||||
var callback = function(data) {
|
||||
console.log(data);
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'PUT',
|
||||
data: params,
|
||||
success: callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
Before Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 120 B |
|
Before Width: | Height: | Size: 105 B |
|
Before Width: | Height: | Size: 111 B |
|
Before Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 101 B |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
|
@ -1,195 +0,0 @@
|
|||
html, body {
|
||||
height: 100%;
|
||||
overflow:hidden;
|
||||
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333;
|
||||
}
|
||||
.schedule-content {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
width: 125px;
|
||||
display : inline-block;
|
||||
background: #009ed8;
|
||||
|
||||
}
|
||||
|
||||
li:hover ul {
|
||||
display:block;
|
||||
}
|
||||
|
||||
li a {
|
||||
display: block;
|
||||
padding: 5px 10px 5px 10px;
|
||||
text-decoration: none;
|
||||
border-right: 0px solid black;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
li a:hover {
|
||||
background: #80dcff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.active {
|
||||
background: #1A6907;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
li ul {
|
||||
margin-left: 85px;
|
||||
margin-top: -25px;
|
||||
position: absolute;
|
||||
display: none;
|
||||
z-index: 99;
|
||||
display : inline-block;
|
||||
|
||||
}
|
||||
|
||||
li:hover ul {
|
||||
visibility: block;
|
||||
}
|
||||
|
||||
li ul li {
|
||||
float: none;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
li ul li a {
|
||||
width: auto;
|
||||
background: #009ed8;
|
||||
}
|
||||
|
||||
li ul li a:hover {
|
||||
background: #80dcff;
|
||||
color: #fff;
|
||||
}
|
||||
.schedule-dates-header {
|
||||
position:absolute;
|
||||
top:50px;
|
||||
left: 180px;
|
||||
right:0px;
|
||||
|
||||
}
|
||||
.unscheduled {
|
||||
border:1px solid #bbb;
|
||||
margin-right: 10px;
|
||||
top:100px;
|
||||
left:10px;
|
||||
width:200px;
|
||||
bottom:50px;
|
||||
position:absolute;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 700px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.schedule-rooms-container {
|
||||
position:absolute;
|
||||
top:100px;
|
||||
left:220px;
|
||||
right:0px;
|
||||
bottom:50px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.schedule {
|
||||
}
|
||||
|
||||
.schedule-room-column-header {
|
||||
float:left;
|
||||
padding-top:4px;
|
||||
text-align:center;
|
||||
width: 200px;
|
||||
position: relative;
|
||||
background: #C4E2E2;
|
||||
}
|
||||
|
||||
.unscheduled-header {
|
||||
text-align:center;
|
||||
padding-top:4px;
|
||||
width: 200px;
|
||||
position: relative;
|
||||
background: #111953;
|
||||
color: white;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
|
||||
.schedule-time-column-header {
|
||||
float:left;
|
||||
padding-top:4px;
|
||||
width: 200px;
|
||||
position: relative;
|
||||
background: #C4E2E2;
|
||||
}
|
||||
|
||||
.schedule-time-column {
|
||||
border:1px solid #bbb;
|
||||
float:left;
|
||||
position:relative;
|
||||
width:100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.schedule-room-column {
|
||||
border:1px solid #bbb;
|
||||
float:left;
|
||||
position:relative;
|
||||
width:200px;
|
||||
}
|
||||
|
||||
.schedule-time-slot {
|
||||
border-bottom: 1px solid #bbb;
|
||||
float:left;
|
||||
position:relative;
|
||||
width:100px;
|
||||
height:30px;
|
||||
}
|
||||
|
||||
.schedule-room-slot {
|
||||
border-bottom: 1px solid #bbb;
|
||||
float:left;
|
||||
position:relative;
|
||||
width:200px;
|
||||
height:30px;
|
||||
}
|
||||
|
||||
.schedule-event {
|
||||
overflow:hidden;
|
||||
text-overflow: ellipsis;
|
||||
position:relative;
|
||||
border: 1px solid #000000;
|
||||
left: 0;
|
||||
width:200px;
|
||||
min-height:32px;
|
||||
background: #6af;
|
||||
color: #000;
|
||||
z-index:1;
|
||||
cursor:move;
|
||||
|
||||
}
|
||||
|
||||
.schedule-event-delete-button {
|
||||
position:absolute;
|
||||
top:3px;
|
||||
right:4px;
|
||||
font-weight:bold;
|
||||
cursor:pointer
|
||||
}
|
||||
121
spec/controllers/admin/event_schedules_controller_spec.rb
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Admin::EventSchedulesController do
|
||||
let(:venue) { create(:venue) }
|
||||
let(:conference) { create(:conference, venue: venue) }
|
||||
let(:room) { create(:room, venue: venue) }
|
||||
let(:schedule) { create(:schedule, program: conference.program)}
|
||||
let(:event_schedule) { create(:event_schedule, schedule: schedule)}
|
||||
let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) }
|
||||
let(:organizer) { create(:user, role_ids: organizer_role.id) }
|
||||
|
||||
context 'logged in as an organizer' do
|
||||
before :each do
|
||||
sign_in(organizer)
|
||||
event_schedule
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
context 'with valid attributes' do
|
||||
let(:create_action) do
|
||||
post :create, conference_id: conference.short_title, event_schedule:
|
||||
attributes_for(:event_schedule,
|
||||
schedule_id: schedule.id,
|
||||
event_id: create(:event, program: conference.program).id,
|
||||
room_id: create(:room, venue: venue).id,
|
||||
start_time: conference.start_date)
|
||||
end
|
||||
|
||||
it 'saves the event schedule to the database' do
|
||||
expect{ create_action }.to change { EventSchedule.count }.by 1
|
||||
end
|
||||
|
||||
it 'has 200 status code' do
|
||||
create_action
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid attributes' do
|
||||
|
||||
let(:create_action) do
|
||||
post :create, conference_id: conference.short_title, event_schedule:
|
||||
attributes_for(:event_schedule,
|
||||
schedule_id: schedule.id,
|
||||
event_id: nil,
|
||||
room_id: nil,
|
||||
start_time: nil)
|
||||
end
|
||||
|
||||
it 'does not save the event schedule to the database' do
|
||||
expect{ create_action }.to_not change { EventSchedule.count }
|
||||
end
|
||||
|
||||
it 'has 422 status code' do
|
||||
create_action
|
||||
expect(response.status).to eq(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #update' do
|
||||
context 'with valid attributes' do
|
||||
before :each do
|
||||
patch :update, id: event_schedule.id, conference_id: conference.short_title, event_schedule:
|
||||
attributes_for(:event_schedule,
|
||||
schedule_id: schedule.id,
|
||||
event_id: create(:event, program: conference.program).id,
|
||||
room_id: room.id,
|
||||
start_time: conference.start_date)
|
||||
event_schedule.reload
|
||||
end
|
||||
|
||||
it 'updates the room' do
|
||||
expect(event_schedule.room_id).to eq(room.id)
|
||||
end
|
||||
|
||||
it 'updates the start_time' do
|
||||
expect(event_schedule.start_time).to eq(conference.start_date)
|
||||
end
|
||||
|
||||
it 'has 200 status code' do
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid attributes' do
|
||||
let(:update_action) do
|
||||
patch :update, id: event_schedule.id, conference_id: conference.short_title, event_schedule:
|
||||
attributes_for(:event_schedule,
|
||||
schedule_id: schedule.id,
|
||||
event_id: nil,
|
||||
room_id: nil,
|
||||
start_time: nil)
|
||||
end
|
||||
it 'does not save the event schedule to the database' do
|
||||
expect{ update_action }.to_not change { event_schedule }
|
||||
end
|
||||
|
||||
it 'has 422 status code' do
|
||||
update_action
|
||||
expect(response.status).to eq(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:destroy_action) do
|
||||
delete :destroy, id: event_schedule.id, conference_id: conference.short_title
|
||||
end
|
||||
|
||||
it 'deletes the event schedule' do
|
||||
expect{ destroy_action }.to change { EventSchedule.count }.by(-1)
|
||||
end
|
||||
|
||||
it 'has 200 status code' do
|
||||
destroy_action
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
63
spec/controllers/admin/schedules_controller_spec.rb
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Admin::SchedulesController do
|
||||
let(:conference) { create(:conference) }
|
||||
let(:schedule) { create(:schedule, program: conference.program)}
|
||||
let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) }
|
||||
let(:organizer) { create(:user, role_ids: organizer_role.id) }
|
||||
|
||||
context 'logged in as an organizer' do
|
||||
before :each do
|
||||
sign_in(organizer)
|
||||
schedule
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'renders the index template' do
|
||||
get :index, conference_id: conference.short_title
|
||||
expect(response).to render_template :index
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:create_action){ post :create, conference_id: conference.short_title }
|
||||
|
||||
it 'saves the schedule to the database' do
|
||||
expect{ create_action }.to change { Schedule.count }.by 1
|
||||
end
|
||||
|
||||
it 'redirects to schedules#show' do
|
||||
create_action
|
||||
expect(response).to redirect_to admin_conference_schedule_path(
|
||||
conference.short_title, assigns[:schedule])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:show_action){ get :show, id: schedule.id, conference_id: conference.short_title }
|
||||
|
||||
it 'assigns the requested schedule to schedule' do
|
||||
show_action
|
||||
expect(assigns(:schedule)).to eq schedule
|
||||
end
|
||||
|
||||
it 'renders the show template' do
|
||||
show_action
|
||||
expect(response).to render_template :show
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:destroy_action){ delete :destroy, id: schedule.id, conference_id: conference.short_title }
|
||||
|
||||
it 'deletes the schedule' do
|
||||
expect{ destroy_action }.to change { Schedule.count }.by(-1)
|
||||
end
|
||||
|
||||
it 'redirects to schedules#index' do
|
||||
destroy_action
|
||||
expect(response).to redirect_to admin_conference_schedules_path(conference.short_title)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -26,29 +26,6 @@ describe ConferenceController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #schedule' do
|
||||
context 'XML' do
|
||||
before :each do
|
||||
conference.program.schedule_public = true
|
||||
conference.program.save!
|
||||
create(:event_scheduled, program: conference.program)
|
||||
create(:event_scheduled, program: conference.program)
|
||||
|
||||
get :schedule, id: conference.short_title, format: :xml
|
||||
end
|
||||
|
||||
it 'assigns variables' do
|
||||
expect(assigns(:conference)).to eq conference
|
||||
expect(assigns(:events_xml)).to eq conference.program.events.scheduled.
|
||||
group_by{ |event| event.start_time.to_date }
|
||||
end
|
||||
|
||||
it 'renders successfully' do
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'OPTIONS #index' do
|
||||
it 'Response code is 200' do
|
||||
process :index, 'OPTIONS'
|
||||
|
|
|
|||
28
spec/controllers/schedules_controller_spec.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe SchedulesController do
|
||||
let(:conference) { create(:conference, splashpage: create(:splashpage, public: true), venue: create(:venue)) }
|
||||
|
||||
describe 'GET #show' do
|
||||
context 'XML' do
|
||||
before :each do
|
||||
conference.program.schedule_public = true
|
||||
conference.program.save!
|
||||
create(:event_scheduled, program: conference.program)
|
||||
create(:event_scheduled, program: conference.program)
|
||||
|
||||
get :show, conference_id: conference.short_title, format: :xml
|
||||
end
|
||||
|
||||
it 'assigns variables' do
|
||||
expect(assigns(:conference)).to eq conference
|
||||
expect(assigns(:events_xml)).to eq conference.program.selected_event_schedules.map(&:event)
|
||||
.group_by{ |event| event.time.to_date }
|
||||
end
|
||||
|
||||
it 'has 200 status code' do
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
24
spec/factories/event_schedule.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Read about factories at https://github.com/thoughtbot/factory_girl
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :event_schedule do
|
||||
event
|
||||
after(:build) do |event_schedule|
|
||||
program = event_schedule.event.program
|
||||
unless (venue = program.conference.venue)
|
||||
venue = create(:venue, conference: program.conference)
|
||||
end
|
||||
(event_schedule.room = create(:room, venue: venue)) unless event_schedule.room.present?
|
||||
(event_schedule.start_time = program.conference.start_date.to_time) unless event_schedule.start_time.present?
|
||||
unless event_schedule.schedule.present?
|
||||
unless program.selected_schedule.present?
|
||||
schedule = create(:schedule, program: program)
|
||||
program.schedules << schedule
|
||||
program.selected_schedule = schedule
|
||||
program.save!
|
||||
end
|
||||
event_schedule.schedule = program.selected_schedule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -18,22 +18,20 @@ FactoryGirl.define do
|
|||
factory :event_full do
|
||||
difficulty_level
|
||||
track
|
||||
room
|
||||
after(:build) do |event|
|
||||
event.commercials << build(:event_commercial, commercialable: event)
|
||||
event.difficulty_level = build(:difficulty_level, program: event.program)
|
||||
event.track = build(:track, program: event.program)
|
||||
unless (venue = event.program.conference.venue)
|
||||
venue = create(:venue, conference: event.program.conference)
|
||||
unless event.program.conference.venue
|
||||
create(:venue, conference: event.program.conference)
|
||||
end
|
||||
event.room = build(:room, venue: venue)
|
||||
event.comment_threads << build(:comment, commentable: event)
|
||||
end
|
||||
|
||||
factory :event_scheduled do
|
||||
after(:build) do |event|
|
||||
event.state = 'confirmed'
|
||||
event.start_time = event.program.conference.start_date.to_time
|
||||
event.event_schedules << build(:event_schedule, event: event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
7
spec/factories/schedule.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Read about factories at https://github.com/thoughtbot/factory_girl
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :schedule do
|
||||
program
|
||||
end
|
||||
end
|
||||
|
|
@ -39,7 +39,7 @@ feature 'Has correct abilities' do
|
|||
expect(page).to have_link('Commercials', href: "/admin/conference/#{conference1.short_title}/commercials")
|
||||
expect(page).to have_link('Events', href: "/admin/conference/#{conference1.short_title}/program/events")
|
||||
expect(page).to have_link('Registrations', href: "/admin/conference/#{conference1.short_title}/registrations")
|
||||
expect(page).to have_link('Schedule', href: "/admin/conference/#{conference1.short_title}/schedule")
|
||||
expect(page).to have_link('Schedules', href: "/admin/conference/#{conference1.short_title}/schedules")
|
||||
expect(page).to have_link('Campaigns', href: "/admin/conference/#{conference1.short_title}/campaigns")
|
||||
expect(page).to have_link('Goals', href: "/admin/conference/#{conference1.short_title}/targets")
|
||||
expect(page).to have_link('Venue', href: "/admin/conference/#{conference1.short_title}/venue")
|
||||
|
|
@ -69,8 +69,8 @@ feature 'Has correct abilities' do
|
|||
visit admin_conference_program_events_path(conference1.short_title)
|
||||
expect(current_path).to eq(admin_conference_program_events_path(conference1.short_title))
|
||||
|
||||
visit admin_conference_schedule_path(conference1.short_title)
|
||||
expect(current_path).to eq(admin_conference_schedule_path(conference1.short_title))
|
||||
visit admin_conference_schedules_path(conference1.short_title)
|
||||
expect(current_path).to eq(admin_conference_schedules_path(conference1.short_title))
|
||||
|
||||
visit admin_conference_campaigns_path(conference1.short_title)
|
||||
expect(current_path).to eq(admin_conference_campaigns_path(conference1.short_title))
|
||||
|
|
@ -117,7 +117,7 @@ feature 'Has correct abilities' do
|
|||
expect(page).to have_link('Commercials', href: "/admin/conference/#{conference2.short_title}/commercials")
|
||||
expect(page).to have_link('Events', href: "/admin/conference/#{conference2.short_title}/program/events")
|
||||
expect(page).to_not have_link('Registrations', href: "/admin/conference/#{conference2.short_title}/registrations")
|
||||
expect(page).to have_link('Schedule', href: "/admin/conference/#{conference2.short_title}/schedule")
|
||||
expect(page).to_not have_link('Schedules', href: "/admin/conference/#{conference2.short_title}/schedules")
|
||||
expect(page).to_not have_link('Campaigns', href: "/admin/conference/#{conference2.short_title}/campaigns")
|
||||
expect(page).to_not have_link('Goals', href: "/admin/conference/#{conference2.short_title}/targets")
|
||||
expect(page).to have_link('Venue', href: "/admin/conference/#{conference2.short_title}/venue")
|
||||
|
|
@ -147,8 +147,8 @@ feature 'Has correct abilities' do
|
|||
visit admin_conference_program_events_path(conference2.short_title)
|
||||
expect(current_path).to eq(admin_conference_program_events_path(conference2.short_title))
|
||||
|
||||
visit admin_conference_schedule_path(conference2.short_title)
|
||||
expect(current_path).to eq(admin_conference_schedule_path(conference2.short_title))
|
||||
visit admin_conference_schedules_path(conference2.short_title)
|
||||
expect(current_path).to eq(root_path)
|
||||
|
||||
visit admin_conference_campaigns_path(conference2.short_title)
|
||||
expect(current_path).to eq(root_path)
|
||||
|
|
@ -191,7 +191,7 @@ feature 'Has correct abilities' do
|
|||
expect(page).to have_link('Commercials', href: "/admin/conference/#{conference3.short_title}/commercials")
|
||||
expect(page).to_not have_link('Events', href: "/admin/conference/#{conference3.short_title}/program/events")
|
||||
expect(page).to have_link('Registrations', href: "/admin/conference/#{conference3.short_title}/registrations")
|
||||
expect(page).to_not have_link('Schedule', href: "/admin/conference/#{conference3.short_title}/schedule")
|
||||
expect(page).to_not have_link('Schedules', href: "/admin/conference/#{conference3.short_title}/schedules")
|
||||
expect(page).to_not have_link('Campaigns', href: "/admin/conference/#{conference3.short_title}/campaigns")
|
||||
expect(page).to_not have_link('Targets', href: "/admin/conference/#{conference3.short_title}/targets")
|
||||
expect(page).to_not have_link('Venue', href: "/admin/conference/#{conference3.short_title}/venue")
|
||||
|
|
@ -221,7 +221,7 @@ feature 'Has correct abilities' do
|
|||
visit admin_conference_program_events_path(conference3.short_title)
|
||||
expect(current_path).to eq(root_path)
|
||||
|
||||
visit admin_conference_schedule_path(conference3.short_title)
|
||||
visit admin_conference_schedules_path(conference3.short_title)
|
||||
expect(current_path).to eq(root_path)
|
||||
|
||||
visit admin_conference_campaigns_path(conference3.short_title)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ describe 'User' do
|
|||
let(:conference_with_closed_registration) { create(:conference) }
|
||||
let!(:closed_registration_period) { create(:registration_period, conference: conference_with_closed_registration, start_date: Date.current - 6.days, end_date: Date.current - 6.days) }
|
||||
|
||||
let!(:my_schedule) { create(:schedule, program: my_conference.program) }
|
||||
let!(:other_schedule) { create(:schedule, program: conference_public.program) }
|
||||
|
||||
let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) }
|
||||
let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) }
|
||||
# Test abilities for not signed in users
|
||||
context 'when user is not signed in' do
|
||||
it{ should be_able_to(:index, Conference)}
|
||||
|
|
@ -196,6 +201,10 @@ describe 'User' do
|
|||
it{ should_not be_able_to(:manage, conference_public.questions.first) }
|
||||
it{ should be_able_to(:manage, my_conference.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, conference_public.program.cfp) }
|
||||
it{ should be_able_to(:manage, my_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_schedule) }
|
||||
it{ should be_able_to(:manage, my_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_event_schedule) }
|
||||
it{ should be_able_to(:manage, my_conference.venue) }
|
||||
it{ should_not be_able_to(:manage, conference_public.venue) }
|
||||
it{ should be_able_to(:manage, my_conference.lodgings.first) }
|
||||
|
|
@ -260,6 +269,10 @@ describe 'User' do
|
|||
it{ should_not be_able_to(:manage, conference_public.questions.first) }
|
||||
it{ should be_able_to(:manage, my_conference.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, conference_public.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, my_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_conference.venue) }
|
||||
it{ should be_able_to(:show, my_conference.venue) }
|
||||
it{ should_not be_able_to(:manage, conference_public.venue) }
|
||||
|
|
@ -318,6 +331,10 @@ describe 'User' do
|
|||
it{ should_not be_able_to(:manage, conference_public.questions.first) }
|
||||
it{ should_not be_able_to(:manage, my_conference.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, conference_public.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, my_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_conference.venue) }
|
||||
it{ should_not be_able_to(:show, my_conference.venue) }
|
||||
it{ should_not be_able_to(:manage, conference_public.venue) }
|
||||
|
|
@ -376,6 +393,10 @@ describe 'User' do
|
|||
it{ should_not be_able_to(:manage, conference_public.questions.first) }
|
||||
it{ should_not be_able_to(:manage, my_conference.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, conference_public.program.cfp) }
|
||||
it{ should_not be_able_to(:manage, my_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, other_event_schedule) }
|
||||
it{ should_not be_able_to(:manage, my_conference.venue) }
|
||||
it{ should_not be_able_to(:show, my_conference.venue) }
|
||||
it{ should_not be_able_to(:manage, conference_public.venue) }
|
||||
|
|
|
|||
21
spec/models/event_schedule_spec.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe EventSchedule do
|
||||
|
||||
describe 'association' do
|
||||
it { should belong_to(:schedule) }
|
||||
it { should belong_to(:event) }
|
||||
it { should belong_to(:room) }
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
it 'has a valid factory' do
|
||||
expect(build(:event_schedule)).to be_valid
|
||||
end
|
||||
|
||||
it { is_expected.to validate_presence_of(:schedule) }
|
||||
it { is_expected.to validate_presence_of(:event) }
|
||||
it { is_expected.to validate_presence_of(:room) }
|
||||
it { is_expected.to validate_presence_of(:start_time) }
|
||||
end
|
||||
end
|
||||
|
|
@ -27,7 +27,10 @@ describe Event do
|
|||
|
||||
describe 'max_attendees_no_more_than_room_size' do
|
||||
before :each do
|
||||
event.room = create(:room, size: 3)
|
||||
unless (venue = event.program.conference.venue)
|
||||
venue = create(:venue, conference: event.program.conference)
|
||||
end
|
||||
create(:event_schedule, event: event, room: create(:room, venue: venue, size: 3))
|
||||
event.require_registration = true
|
||||
end
|
||||
|
||||
|
|
@ -116,8 +119,7 @@ describe Event do
|
|||
describe '#scheduled?' do
|
||||
it { expect(event.scheduled?).to eq false }
|
||||
it 'returns true if the event is scheduled' do
|
||||
event.room = create(:room)
|
||||
event.start_time = conference.start_date.to_time
|
||||
create(:event_schedule, event: event)
|
||||
expect(event.scheduled?).to eq true
|
||||
end
|
||||
end
|
||||
|
|
@ -257,27 +259,6 @@ describe Event do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#as_json' do
|
||||
it 'adds the event\'s room_guid, track_color and length' do
|
||||
event.room = create(:room)
|
||||
event.track = create(:track, color: '#efefef')
|
||||
json_hash = event.as_json(nil)
|
||||
|
||||
expect(json_hash[:room_guid]).to eq(event.room.guid)
|
||||
expect(json_hash[:track_color]).to eq('#EFEFEF')
|
||||
expect(json_hash[:length]).to eq(30)
|
||||
end
|
||||
|
||||
it 'uses correct default values for room_guid, track_color and length' do
|
||||
event.event_type = nil
|
||||
json_hash = event.as_json(nil)
|
||||
|
||||
expect(json_hash[:room_guid]).to be_nil
|
||||
expect(json_hash[:track_color]).to eq('#FFFFFF')
|
||||
expect(json_hash[:length]).to eq(15)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#transition_possible?(transition)' do
|
||||
shared_examples 'transition_possible?(transition)' do |state, transition, expected|
|
||||
it "returns #{expected} for #{transition} transition, when the event is #{state}}" do
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ describe Program do
|
|||
describe 'association' do
|
||||
it { is_expected.to belong_to :conference }
|
||||
it { is_expected.to have_one(:cfp).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:schedules).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:event_types).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:tracks).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:difficulty_levels).dependent(:destroy) }
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ describe Room do
|
|||
|
||||
describe 'association' do
|
||||
it { should belong_to(:venue) }
|
||||
it { should have_many(:events).dependent(:nullify) }
|
||||
it { should have_many(:event_schedules).dependent(:nullify) }
|
||||
end
|
||||
|
||||
describe 'callback' do
|
||||
|
|
|
|||
10
spec/models/schedule_spec.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Schedule do
|
||||
|
||||
describe 'association' do
|
||||
it { should belong_to(:program) }
|
||||
it { should have_many(:event_schedules).dependent(:destroy) }
|
||||
it { should have_many(:events).through(:event_schedules) }
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@ describe EventSerializer, type: :serializer do
|
|||
guid: event.guid,
|
||||
title: 'Some Talk',
|
||||
length: 30,
|
||||
date: '',
|
||||
scheduled_date: '',
|
||||
language: nil,
|
||||
abstract: '<p>Lorem ipsum dolor sit amet</p>',
|
||||
speaker_ids: [],
|
||||
|
|
@ -30,9 +30,9 @@ describe EventSerializer, type: :serializer do
|
|||
let(:track) { create(:track) }
|
||||
|
||||
before do
|
||||
event.update_attributes(start_time: Date.new(2014, 03, 04), language: 'English')
|
||||
event.language = 'English'
|
||||
event.event_users << speaker
|
||||
event.room = room
|
||||
create(:event_schedule, event: event, room: room, start_time: Date.new(2014, 03, 04))
|
||||
event.track = track
|
||||
end
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ describe EventSerializer, type: :serializer do
|
|||
guid: event.guid,
|
||||
title: 'Some Talk',
|
||||
length: 30,
|
||||
date: ' 2014-03-04T00:00:00+0000 ',
|
||||
scheduled_date: ' 2014-03-04T00:00:00+0000 ',
|
||||
language: 'English',
|
||||
abstract: '<p>Lorem ipsum dolor sit amet</p>',
|
||||
speaker_ids: [speaker.user.id],
|
||||
|
|
|
|||