2015-10-25 13:29:02 +02:00
# cannot delete program if there are events submitted
class Program < ActiveRecord :: Base
belongs_to :conference
has_one :cfp , dependent : :destroy
has_many :event_types , dependent : :destroy
has_many :tracks , dependent : :destroy
has_many :difficulty_levels , dependent : :destroy
2016-07-08 13:28:02 +02:00
has_many :schedules , dependent : :destroy
2015-10-25 13:29:02 +02:00
has_many :events , dependent : :destroy do
2016-04-22 18:18:46 +03:00
def require_registration
2015-10-25 13:29:02 +02:00
where ( require_registration : true , state : :confirmed )
end
2016-04-22 18:18:46 +03:00
def with_registration_open
2016-05-15 14:01:30 +03:00
select { | e | e if e . registration_possible? }
2016-04-22 18:18:46 +03:00
end
# All confirmed events of the conference with attribute require_registration
# excluding the events the user has already registered to
def remaining_for_registration ( registration )
require_registration - registration . events
end
2015-10-25 13:29:02 +02:00
def confirmed
where ( state : :confirmed )
end
2016-07-08 13:28:02 +02:00
def scheduled ( schedule_id )
joins ( :event_schedules ) . where ( 'event_schedules.schedule_id = ? AND event_schedules.start_time IS NOT NULL AND event_schedules.room_id IS NOT NULL' , schedule_id )
2015-10-25 13:29:02 +02:00
end
2016-06-11 00:43:45 +02:00
def unscheduled
2016-07-08 13:28:02 +02:00
select ( & :unscheduled? )
2016-06-11 00:43:45 +02:00
end
2015-10-25 13:29:02 +02:00
def highlights
where ( state : :confirmed , is_highlight : true )
end
end
has_many :event_users , through : :events
has_many :speakers , - > { distinct } , through : :event_users , source : :user do
def confirmed
joins ( :events ) . where ( events : { state : :confirmed } )
end
end
accepts_nested_attributes_for :event_types , allow_destroy : true
accepts_nested_attributes_for :tracks , reject_if : proc { | r | r [ 'name' ] . blank? } , allow_destroy : true
accepts_nested_attributes_for :difficulty_levels , allow_destroy : true
# validates :conference_id, presence: true, uniqueness: true
2016-07-05 16:44:53 +03:00
validates :rating , numericality : { greater_than_or_equal_to : 0 , less_than_or_equal_to : 10 , only_integer : true }
validate :voting_start_date_before_end_date
validate :voting_dates_exist
2015-10-25 13:29:02 +02:00
before_create :create_event_types
before_create :create_difficulty_levels
2016-03-21 00:18:20 +01:00
validate :check_languages_format
2015-10-25 13:29:02 +02:00
2016-07-05 16:44:53 +03:00
##
# Checks if blind_voting is enabled and if voting period is over
# ====Returns
# * +true+ -> If we can show voting details
# * +false+ -> If we cannot show voting details
def show_voting?
return true unless blind_voting
Date . today > voting_end_date
end
##
# Checks if we are still in voting period
# ====Returns
# * +true+ -> If the voting period is not over yet
# * +false+ -> If the voting period is over
def voting_period?
return false unless voting_start_date && voting_end_date
( voting_start_date . to_datetime .. voting_end_date . to_datetime ) . cover? Time . current
end
##
# Checks if both voting_start_date and voting_end_date are set
# ====Returns
# Errors when the condition is not true
def voting_dates_exist
errors . add ( :voting_start_date , 'must be set, when blind voting is enabled' ) if blind_voting && ! voting_start_date && ! voting_end_date
errors . add ( :voting_end_date , 'must be set, when blind voting is enabled' ) if blind_voting && ! voting_start_date && ! voting_end_date
errors . add ( :voting_end_date , 'must be set, when voting_start_date is set' ) if voting_start_date && ! voting_end_date
errors . add ( :voting_start_date , 'must be set, when voting_end_date is set' ) if voting_end_date && ! voting_start_date
end
##
# Checks if voting_start_date is before voting_end_date
# ====Returns
# Errors when the condition is not true
def voting_start_date_before_end_date
errors . add ( :voting_start_date , 'must be before voting end date' ) if voting_start_date && voting_end_date && voting_start_date > voting_end_date
end
2015-10-25 13:29:02 +02:00
##
# Checcks if the program has rating enabled
#
# ====Returns
# * +false+ -> If rating is not enabled
# * +true+ -> If rating is enabled
def rating_enabled?
self . rating && self . rating > 0
end
##
# Checks if the call for papers for the conference is currently open
#
# ====Returns
# * +false+ -> If the CFP is not set or today isn't in the CFP period.
# * +true+ -> If today is in the CFP period.
def cfp_open?
cfp = self . cfp
cfp . present? && ( cfp . start_date .. cfp . end_date ) . cover? ( Date . current )
end
2016-03-31 16:51:16 +02:00
def notify_on_schedule_public?
return false unless conference . email_settings . send_on_program_schedule_public
# do not notify if the schedule is not public
return false unless schedule_public
# do not notify unless the mail content is set up
( ! conference . email_settings . program_schedule_public_subject . blank? && ! conference . email_settings . program_schedule_public_body . blank? )
end
2016-03-21 00:18:20 +01:00
def languages_list
self . languages . split ( ',' ) . map { | l | ISO_639 . find ( l ) . english_name } if self . languages . present?
end
2016-06-12 21:37:16 +02:00
##
# Checks if there is any event in the program that starts in the given date
#
# ====Returns
# * +True+ -> If there is any event for the given date
# * +False+ -> If there is not any event for the given date
def any_event_for_this_date? ( date )
parsed_date = DateTime . parse ( " #{ date } 00:00 " ) . utc
events . where ( start_time : parsed_date .. ( parsed_date + 1 ) ) . any?
end
2015-10-25 13:29:02 +02:00
private
##
# Creates default EventTypes for this Conference. Used as before_create.
#
def create_event_types
event_types << EventType . create ( title : 'Talk' , length : 30 , color : '#FF0000' , description : 'Presentation in lecture format' ,
minimum_abstract_length : 0 ,
maximum_abstract_length : 500 )
event_types << EventType . create ( title : 'Workshop' , length : 60 , color : '#0000FF' , description : 'Interactive hands-on practice' ,
minimum_abstract_length : 0 ,
maximum_abstract_length : 500 )
true
end
##
# Creates default DifficultyLevels for this Conference. Used as before_create.
#
def create_difficulty_levels
difficulty_levels << DifficultyLevel . create ( title : 'Easy' ,
description : 'Events are understandable for everyone without knowledge of the topic.' ,
color : '#70EF69' )
difficulty_levels << DifficultyLevel . create ( title : 'Medium' ,
description : 'Events require a basic understanding of the topic.' ,
color : '#EEEF69' )
difficulty_levels << DifficultyLevel . create ( title : 'Hard' ,
description : 'Events require expert knowledge of the topic.' ,
color : '#EF6E69' )
true
end
2016-03-21 00:18:20 +01:00
##
# Check if languages string has the right format. Used as validation.
#
def check_languages_format
return unless self . languages . present?
# All white spaces are removed to allow languages to be separated by ',' and ', '. The languages string without spaces is saved
self . languages = self . languages . delete ( ' ' ) . downcase
errors . add ( :languages , 'must be two letters separated by commas' ) && return unless
self . languages . match ( / ^$|( \ A[a-z][a-z](,[a-z][a-z])* \ z) / ) . present?
languages_array = self . languages . split ( ',' )
# We check that languages are not repeated
errors . add ( :languages , " can't be repeated " ) && return unless languages_array . uniq! . nil?
# 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
2015-10-25 13:29:02 +02:00
end