mirror of
https://github.com/openSUSE/osem.git
synced 2026-08-13 19:54:02 +00:00
Merge pull request #1319 from JewelSam/master
#1220 adding the cell size attribute to the database
This commit is contained in:
commit
f3e712a1bc
19 changed files with 104 additions and 35 deletions
|
|
@ -43,7 +43,6 @@ There are a couple of environment variables you can set to configure OSEM. Check
|
|||
| OSEM_FACEBOOK_SECRET | *string* | OMNIAUTH Developer Secret for Facebook
|
||||
| OSEM_GITHUB_KEY | *string* | OMNIAUTH Developer Key for GitHub
|
||||
| OSEM_GITHUB_SECRET | *string* | OMNIAUTH Developer Secret for GitHub
|
||||
| OSEM_SCHEDULE_CELL_SIZE | *integer* | Schedule timeslot size to use (in minutes), should be greater than zero, should be divisor of 60
|
||||
| OSEM_SMTP_ADDRESS | smtp.opensuse.org | The smtp server to use
|
||||
| OSEM_SMTP_PORT | *int* | The port on the smtp server
|
||||
| OSEM_SMTP_USERNAME | *string* | The user for the smtp server
|
||||
|
|
|
|||
4
app.json
4
app.json
|
|
@ -54,10 +54,6 @@
|
|||
"description": "The user for the smtp server",
|
||||
"required": false
|
||||
},
|
||||
"OSEM_SCHEDULE_CELL_SIZE": {
|
||||
"description": "Schedule timeslot size in minutes",
|
||||
"required": false
|
||||
},
|
||||
"RACK_ENV": {
|
||||
"required": false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,13 +12,15 @@ module Admin
|
|||
@program = @conference.program
|
||||
@program.assign_attributes(program_params)
|
||||
send_mail_on_schedule_public = @program.notify_on_schedule_public?
|
||||
event_schedules_count_was = @program.event_schedules.count
|
||||
|
||||
if @program.update_attributes(program_params)
|
||||
ConferenceScheduleUpdateMailJob.perform_later(@conference) if send_mail_on_schedule_public
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to admin_conference_program_path(@conference.short_title),
|
||||
notice: 'The program was successfully updated.'
|
||||
notice = 'The program was successfully updated.'
|
||||
notice += ' You changed schedule interval and some events were unscheduled.' if @program.event_schedules.count != event_schedules_count_was
|
||||
redirect_to admin_conference_program_path(@conference.short_title), notice: notice
|
||||
end
|
||||
format.js { render json: {} }
|
||||
end
|
||||
|
|
@ -36,7 +38,7 @@ module Admin
|
|||
private
|
||||
|
||||
def program_params
|
||||
params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date, :selected_schedule_id)
|
||||
params.require(:program).permit(:rating, :schedule_public, :schedule_interval, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date, :selected_schedule_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class SchedulesController < ApplicationController
|
|||
|
||||
@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
|
||||
@step_minutes = @program.schedule_interval.minutes
|
||||
@conf_start = @conference.start_hour
|
||||
@conf_period = @conference.end_hour - @conf_start
|
||||
|
||||
|
|
|
|||
|
|
@ -15,17 +15,13 @@ class EventType < ActiveRecord::Base
|
|||
|
||||
alias_attribute :name, :title
|
||||
|
||||
# If LENGTH_STEP must be divisor of 60, otherwise the schedule wont be displayed properly
|
||||
|
||||
LENGTH_STEP = defined?(SCHEDULE_CELL_SIZE) ? SCHEDULE_CELL_SIZE : 15
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Check if length is multiple of LENGTH_STEP. Used as validation.
|
||||
# Check if length is a divisor of program schedule cell size. Used as validation.
|
||||
#
|
||||
def length_step
|
||||
errors.add(:length, "must be multiple of #{LENGTH_STEP}") if length % LENGTH_STEP != 0
|
||||
errors.add(:length, "must be a divisor of #{program.schedule_interval}") if program && length % program.schedule_interval != 0
|
||||
end
|
||||
|
||||
def capitalize_color
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class Program < ActiveRecord::Base
|
|||
where(state: :confirmed, is_highlight: true)
|
||||
end
|
||||
end
|
||||
has_many :event_schedules, through: :events
|
||||
|
||||
has_many :event_users, through: :events
|
||||
has_many :speakers, -> { distinct }, through: :event_users, source: :user do
|
||||
|
|
@ -52,11 +53,15 @@ class Program < ActiveRecord::Base
|
|||
|
||||
# validates :conference_id, presence: true, uniqueness: true
|
||||
validates :rating, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 10, only_integer: true }
|
||||
validates :schedule_interval, numericality: { greater_than_or_equal_to: 5, less_than_or_equal_to: 60 }, presence: true
|
||||
validate :schedule_interval_divisor_60
|
||||
validate :voting_start_date_before_end_date
|
||||
validate :voting_dates_exist
|
||||
|
||||
after_create :create_event_types
|
||||
after_create :create_difficulty_levels
|
||||
after_save :unschedule_unfit_events, if: :schedule_interval_changed?
|
||||
after_save :normalize_event_types_length, if: :schedule_interval_changed?
|
||||
validate :check_languages_format
|
||||
|
||||
# Returns all event_schedules for the selected schedule ordered by start_time
|
||||
|
|
@ -199,4 +204,31 @@ class Program < ActiveRecord::Base
|
|||
# We check if every language is a valid ISO 639-1 language
|
||||
errors.add(:languages, 'must be ISO 639-1 valid codes') unless languages_array.select{ |x| ISO_639.find(x).nil? }.empty?
|
||||
end
|
||||
|
||||
##
|
||||
# Check if schedule_interval is a divisor of 60 minutes
|
||||
#
|
||||
def schedule_interval_divisor_60
|
||||
errors.add(:schedule_interval, 'must be a divisor of 60') if schedule_interval > 0 && 60 % schedule_interval > 0
|
||||
end
|
||||
|
||||
##
|
||||
# Unschedule all the events which don't fit
|
||||
#
|
||||
def unschedule_unfit_events
|
||||
unfit_schedules = event_schedules.select do |event_schedule|
|
||||
event_schedule.start_time.min % schedule_interval > 0
|
||||
end
|
||||
EventSchedule.where(id: unfit_schedules.map(&:id)).destroy_all
|
||||
end
|
||||
|
||||
##
|
||||
# Change event type length according schedule interval
|
||||
#
|
||||
def normalize_event_types_length
|
||||
event_types.each do |event_type|
|
||||
new_length = event_type.length > schedule_interval ? event_type.length - (event_type.length % schedule_interval) : schedule_interval
|
||||
event_type.update_attributes length: new_length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,6 @@ class EventSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def length
|
||||
object.event_type.try(:length) || EventType::LENGTH_STEP
|
||||
object.event_type.try(:length) || object.event_type.program.schedule_interval
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
.col-md-12
|
||||
= semantic_form_for(@event_type, url: (@event_type.new_record? ? admin_conference_program_event_types_path : admin_conference_program_event_type_path(@conference.short_title, @event_type))) do |f|
|
||||
= f.input :title
|
||||
= f.input :length, input_html: {size: 3, type: 'number', step: EventType::LENGTH_STEP, min: EventType::LENGTH_STEP}
|
||||
= f.input :length, input_html: {size: 3, type: 'number', step: @event_type.program.schedule_interval, min: @event_type.program.schedule_interval}
|
||||
= f.input :description
|
||||
= f.input :minimum_abstract_length, input_html: {size: 3}
|
||||
= f.input :maximum_abstract_length, input_html: {size: 3}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
= f.input :schedule_fluid, label: 'Allow submitters to change their event after it is scheduled'
|
||||
= f.input :rating, hint: 'Enter the number of different rating levels you want to have for voting on proposals. Enter 0 if you do not want to vote on proposals.'
|
||||
= f.input :languages, hint: "Enter the languages allowed for events as values of #{link_to('ISO 639-1', 'http://www.loc.gov/standards/iso639-2/php/code_list.php', target: "_blank")} language codes separated with commas. The first language would be the default language. Leave it blank if you do not want to specify languages.".html_safe
|
||||
= f.input :schedule_interval, hint: "It is the minimal time interval of your schedule. The value should be 5, 6, 10, 12, 15, 20, 30 or 60. Warning! Some events could be unscheduled when changing this value."
|
||||
= f.input :blind_voting, hint: 'Enable this feature if you do not want to show voting results and voters prior to user submitting a vote. For the feature to work you need to set the voting dates below as well'
|
||||
= f.input :voting_start_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_start_date.to_formatted_s(:db_without_seconds) unless f.object.voting_start_date.nil?) }
|
||||
= f.input :voting_end_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_end_date.to_formatted_s(:db_without_seconds) unless f.object.voting_end_date.nil?) }
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@
|
|||
Yes
|
||||
- else
|
||||
No
|
||||
%dt
|
||||
Schedule interval
|
||||
%dd
|
||||
= @program.schedule_interval
|
||||
minutes
|
||||
|
||||
%h3 Voting Options
|
||||
%hr
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
- compact_grid = EventType::LENGTH_STEP < 15
|
||||
- cells_per_hour = 60 / EventType::LENGTH_STEP
|
||||
- compact_grid = @program.schedule_interval < 15
|
||||
- cells_per_hour = 60 / @program.schedule_interval
|
||||
/ use smaller cell heights for more compact grids
|
||||
- cell_height = compact_grid ? 32 : 58
|
||||
- date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date }
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
= room.name
|
||||
- (@conference.start_hour * cells_per_hour..@conference.end_hour * cells_per_hour).each do |slot|
|
||||
- hour = slot / cells_per_hour
|
||||
- minutes = (EventType::LENGTH_STEP * (slot % cells_per_hour)).to_s.rjust(2, '0')
|
||||
- minutes = (@program.schedule_interval * (slot % cells_per_hour)).to_s.rjust(2, '0')
|
||||
- time = "#{hour}:#{minutes}"
|
||||
.schedule-room-slot{ id: "schedule-room-#{room.guid}-#{hour}-#{minutes}", |
|
||||
room_id: room.id, |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
- cells_length = event.event_type.length / EventType::LENGTH_STEP
|
||||
- cells_length = event.event_type.length / @program.schedule_interval
|
||||
/ this height fits the room cells
|
||||
- compact_grid = EventType::LENGTH_STEP < 15
|
||||
- compact_grid = @program.schedule_interval < 15
|
||||
- single_cell_height = compact_grid ? 32 : 58
|
||||
- height = (cells_length * single_cell_height)
|
||||
- height -= 23 unless compact_grid
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
- intervals = hrs_per_slide * 60 / EventType::LENGTH_STEP + 1
|
||||
- intervals = hrs_per_slide * 60 / @conference.program.schedule_interval + 1
|
||||
- width = 85 / intervals
|
||||
- carousel_number = (@conf_period / hrs_per_slide.to_f).ceil
|
||||
.carousel.slide{ id: "carousel-#{ date }-#{ hrs_per_slide }", |
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
- if event_schedule
|
||||
/ There is an event, calculate the span and show it
|
||||
- event_span = (event_schedule.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 / @conference.program.schedule_interval
|
||||
- span = ((event_span + i - 1 ) > intervals ? intervals + 1 - i : event_span)
|
||||
= render partial: 'schedule_item', locals: {event: event_schedule.event, event_schedule: event_schedule, span: span, width: width}
|
||||
- else
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
%start= @conference.start_date
|
||||
%end= @conference.end_date
|
||||
%days= (@conference.end_date - @conference.start_date).to_i + 1
|
||||
%timeslot_duration= length_timestamp(EventType::LENGTH_STEP)
|
||||
%timeslot_duration= length_timestamp(@conference.program.schedule_interval)
|
||||
|
||||
- if @events_xml.any?
|
||||
- @events_xml.keys.each.with_index(1) do |day, index|
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#sanitize the OSEM_SCHEUDLE_CELL_SIZE to be used for EventType::LENGTH_STEP
|
||||
sched_cell_size = ENV['OSEM_SCHEDULE_CELL_SIZE'].to_i
|
||||
|
||||
if (sched_cell_size > 0 and 60 % sched_cell_size == 0)
|
||||
SCHEDULE_CELL_SIZE = sched_cell_size
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class AddScheduleIntervalToPrograms < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :programs, :schedule_interval, :integer, default: 15, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20170213145807) do
|
||||
ActiveRecord::Schema.define(version: 20170302145716) do
|
||||
|
||||
create_table "ahoy_events", force: :cascade do |t|
|
||||
t.uuid "visit_id", limit: 16
|
||||
|
|
@ -289,6 +289,7 @@ ActiveRecord::Schema.define(version: 20170213145807) do
|
|||
t.datetime "voting_start_date"
|
||||
t.datetime "voting_end_date"
|
||||
t.integer "selected_schedule_id"
|
||||
t.integer "schedule_interval", default: 15, null: false
|
||||
end
|
||||
|
||||
add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,3 @@ OSEM_SMTP_DOMAIN=""
|
|||
|
||||
# Enable the usage of the devise ichain plugin
|
||||
OSEM_ICHAIN_ENABLED=false
|
||||
|
||||
# Schedule grid parameters, cell size in minutes
|
||||
OSEM_SCHEDULE_CELL_SIZE=15
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ describe Program do
|
|||
it { is_expected.to have_many(:tracks).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:difficulty_levels).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:events).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:event_schedules).through(:events) }
|
||||
it { is_expected.to have_many(:event_users).through(:events) }
|
||||
it { is_expected.to have_many(:speakers).through(:event_users).source(:user) }
|
||||
|
||||
|
|
@ -32,6 +33,18 @@ describe Program do
|
|||
|
||||
it { is_expected.to validate_numericality_of(:rating).is_greater_than_or_equal_to(0).is_less_than_or_equal_to(10).only_integer }
|
||||
|
||||
it { is_expected.to validate_numericality_of(:schedule_interval).is_greater_than_or_equal_to(5).is_less_than_or_equal_to(60) }
|
||||
|
||||
describe 'schedule_interval_divisor_60' do
|
||||
it 'is valid, when schedule_interval is divisor of 60' do
|
||||
expect(build(:program, schedule_interval: 20)).to be_valid
|
||||
end
|
||||
|
||||
it 'is not valid, when schedule_interval is not divisor of 60' do
|
||||
expect(build(:program, schedule_interval: 35)).to_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe 'voting_start_date_before_end_date' do
|
||||
it 'is valid, when voting_start_date is the same day as voting_end_date' do
|
||||
expect(build(:program, voting_start_date: Date.today, voting_end_date: Date.today)).to be_valid
|
||||
|
|
@ -167,6 +180,34 @@ describe Program do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'excecutes after_save functions' do
|
||||
it 'and unschedule unfit events if schedule interval was changed' do
|
||||
start_date = program.conference.start_date.to_datetime.change(hour: program.conference.start_hour)
|
||||
create(:event_schedule, event: create(:event, program: program), start_time: start_date.change(min: program.schedule_interval))
|
||||
create(:event_schedule, event: create(:event, program: program), start_time: start_date)
|
||||
expect(program.event_schedules.count).to eq 2
|
||||
|
||||
program.schedule_interval = 10
|
||||
program.save!
|
||||
program.reload
|
||||
expect(program.event_schedules.count).to eq 1
|
||||
expect(program.event_schedules.first.start_time).to eq start_date
|
||||
end
|
||||
|
||||
it 'and change event type length if schedule interval was changed' do
|
||||
program.schedule_interval = 5
|
||||
program.save!
|
||||
|
||||
program.event_types.first.update_attributes length: 5
|
||||
program.event_types.last.update_attributes length: 25
|
||||
create(:event_type, program: program, length: 30)
|
||||
|
||||
program.schedule_interval = 10
|
||||
program.save!
|
||||
expect(program.event_types.pluck(:length).sort).to eq [10, 20, 30]
|
||||
end
|
||||
end
|
||||
|
||||
describe 'languages' do
|
||||
it "is not valid if languages aren't two letters separated by commas" do
|
||||
program.languages = 'eng, De es'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue