diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 56ff7885..68360907 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -645,6 +645,7 @@ Style/PercentLiteralDelimiters: - 'app/models/contact.rb' - 'app/models/registration.rb' - 'app/models/subscription.rb' + - 'app/models/cfp.rb' - 'app/uploaders/picture_uploader.rb' - 'spec/models/ability_spec.rb' - 'spec/models/program_spec.rb' diff --git a/app/controllers/admin/cfps_controller.rb b/app/controllers/admin/cfps_controller.rb index 42d10218..81fd78a9 100644 --- a/app/controllers/admin/cfps_controller.rb +++ b/app/controllers/admin/cfps_controller.rb @@ -2,7 +2,7 @@ module Admin class CfpsController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true - load_and_authorize_resource through: :program, singleton: true + load_and_authorize_resource through: :program def show; end @@ -27,7 +27,6 @@ module Admin end def update - @cfp = @program.cfp @cfp.assign_attributes(cfp_params) send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update? diff --git a/app/models/cfp.rb b/app/models/cfp.rb index affcc408..92058e87 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -1,6 +1,10 @@ # cannot delete program if there are events submitted class Cfp < ActiveRecord::Base + TYPES = %w(events).freeze + + scope :for_events, (-> { find_by(cfp_type: 'events') }) + has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } belongs_to :program @@ -8,6 +12,15 @@ class Cfp < ActiveRecord::Base validates :start_date, :end_date, presence: true validate :before_end_of_conference validate :start_after_end_date + validates :cfp_type, + presence: true, + inclusion: { + in: TYPES + }, + uniqueness: { + scope: :program, + case_sensitive: false + } ## # Checks whether cfp date is updated @@ -55,6 +68,16 @@ class Cfp < ActiveRecord::Base result > 0 ? result : 0 end + ## + # Checks if the call for papers 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 open? + (start_date..end_date).cover?(Date.current) + end + private def before_end_of_conference diff --git a/app/models/program.rb b/app/models/program.rb index e36d65bf..09bb3627 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -5,7 +5,7 @@ class Program < ActiveRecord::Base belongs_to :conference - has_one :cfp, dependent: :destroy + has_many :cfps, dependent: :destroy has_many :event_types, dependent: :destroy has_many :tracks, dependent: :destroy has_many :difficulty_levels, dependent: :destroy @@ -135,7 +135,7 @@ class Program < ActiveRecord::Base # * +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 = cfps.events cfp.present? && (cfp.start_date..cfp.end_date).cover?(Date.current) end @@ -163,6 +163,23 @@ class Program < ActiveRecord::Base EventSchedule.where(schedule: selected_schedule).where(start_time: parsed_date..(parsed_date + 1)).any? end + ## + # Provides backwards compatibility for when the program had one cfp + # + # ====Returns + # * +ActiveRecord+ -> The program's cfp with cfp_type == 'events' + def cfp + return nil if cfps.for_events.blank? + cfps.for_events + end + + ## + # ====Returns + # * +Array+ -> The types of cfps for which a cfp doesn't exist yet + def remaining_cfp_types + Cfp::TYPES - cfps.pluck(:cfp_type) + end + private ## diff --git a/db/migrate/20170530072155_add_type_to_cfps.rb b/db/migrate/20170530072155_add_type_to_cfps.rb new file mode 100644 index 00000000..50423281 --- /dev/null +++ b/db/migrate/20170530072155_add_type_to_cfps.rb @@ -0,0 +1,15 @@ +class AddTypeToCfps < ActiveRecord::Migration + class TmpCfp < ActiveRecord::Base + self.table_name = 'cfps' + end + + def change + add_column :cfps, :cfp_type, :string + + TmpCfp.reset_column_information + TmpCfp.find_each do |cfp| + cfp.cfp_type = 'events' + cfp.save! + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 19a3df19..348f6170 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -52,6 +52,7 @@ ActiveRecord::Schema.define(version: 20170603095900) do t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" + t.string "cfp_type" end create_table "comments", force: :cascade do |t| diff --git a/spec/models/cfp_spec.rb b/spec/models/cfp_spec.rb index 3f8e7a0f..606f5f9f 100644 --- a/spec/models/cfp_spec.rb +++ b/spec/models/cfp_spec.rb @@ -1,8 +1,24 @@ require 'spec_helper' describe Cfp do + subject { create(:cfp) } let!(:conference) { create(:conference, end_date: Date.today) } - let!(:cfp) { build(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } + let!(:cfp) { create(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } + + describe 'scope' do + describe '#for_events' do + it 'returns the cfp for events' do + expect(conference.program.cfps.for_events).to be_a Cfp + expect(conference.program.cfps.for_events.cfp_type).to eq('events') + end + end + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:cfp_type) } + it { is_expected.to validate_inclusion_of(:cfp_type).in_array(Cfp::TYPES) } + it { is_expected.to validate_uniqueness_of(:cfp_type).scoped_to(:program_id).case_insensitive } + end describe '#before_end_of_conference' do describe 'fails to save cfp' do @@ -97,4 +113,28 @@ describe Cfp do end end end + + describe '#open?' do + context 'returns false' do + it 'when start and end dates are in the past' do + cfp.start_date = Date.current - 3 + cfp.end_date = Date.current - 1 + expect(cfp.open?).to eq(false) + end + + it 'when start and end dates are in the future' do + cfp.start_date = Date.current + 1 + cfp.end_date = Date.current + 3 + expect(cfp.open?).to eq(false) + end + end + + context 'returns true' do + it 'when start date is in the past and end date is in the future' do + cfp.start_date = Date.current - 1 + cfp.end_date = Date.current + 1 + expect(cfp.open?).to eq(true) + end + end + end end diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index a2106791..6ea62cf0 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -240,4 +240,23 @@ describe Program do end end + describe '#cfp' do + it 'returns the cfp for events' do + create(:cfp, cfp_type: 'events', program: program, end_date: Date.current + 1) + expect(program.cfp).to be_a Cfp + expect(program.cfp.cfp_type).to eq('events') + end + + it 'returns nil if the program doesn\'t have a cfp' do + expect(program.cfp).to eq(nil) + end + end + + describe '#remaining_cfp_types' do + it 'returns an array with the types for which a cfp doesn\'t exist' do + expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + create(:cfp, cfp_type: 'events', program: program, end_date: Date.current + 1) + expect(program.remaining_cfp_types).to eq([]) + end + end end