diff --git a/app/assets/javascripts/osem-datepickers.js b/app/assets/javascripts/osem-datepickers.js index 1888da3e..169ff4b6 100644 --- a/app/assets/javascripts/osem-datepickers.js +++ b/app/assets/javascripts/osem-datepickers.js @@ -1,6 +1,14 @@ // get current_date var today = new Date().toISOString().slice(0, 10); $(function () { + $("input[id^='datetimepicker']").datetimepicker({ + pickTime: true, + useCurrent: false, + sideBySide: true, + autoclose: true, + format: 'YYYY-MM-DD HH:mm' + }); + $("#registration-arrival-datepicker").datetimepicker({ pickTime: true, useCurrent: false, @@ -12,7 +20,7 @@ $(function () { minDate : today, defaultDate : $("#registration-arrival-datepicker").attr('start_date'), }); - + $("#registration-departure-datepicker").datetimepicker({ pickTime: true, useCurrent: false, @@ -23,7 +31,7 @@ $(function () { minDate : $("#registration-arrival-datepicker").attr('start_date'), defaultDate : $("#registration-arrival-datepicker").attr('end_date'), }); - + $("#registration-arrival-datepicker").on("dp.change",function (e) { // departure_date > start_date,arrival_date if ((new Date(e.date).getTime()) > (new Date($("#registration-arrival-datepicker").attr('start_date')).getTime())){ @@ -52,7 +60,7 @@ $(function () { useCurrent: false, format: "YYYY-MM-DD", }); - + // end_date_conference >= registration-period-Start_date >= Current_date // registration-period-Start_date <= registration-period-End_date <= End_date (of conference) $("#registration-period-start-datepicker").datetimepicker({ @@ -62,7 +70,7 @@ $(function () { minDate : today, maxDate : $("#registration-period-start-datepicker").attr('end_date'), }); - + $("#registration-period-end-datepicker").datetimepicker({ pickTime: false, useCurrent: false, @@ -70,7 +78,7 @@ $(function () { minDate: today, maxDate : $("#registration-period-start-datepicker").attr('end_date'), }); - + $("#conference-start-datepicker").on("dp.change",function (e) { $('#conference-end-datepicker').data("DateTimePicker").setMinDate(e.date); }); diff --git a/app/controllers/admin/programs_controller.rb b/app/controllers/admin/programs_controller.rb index ba66809f..2cb720b0 100644 --- a/app/controllers/admin/programs_controller.rb +++ b/app/controllers/admin/programs_controller.rb @@ -26,7 +26,7 @@ module Admin private def program_params - params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages) + params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date) end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ddc072af..dcdcc31e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,4 +1,16 @@ module ApplicationHelper + ## + # Checks if the voting has already started, or if it has already ended + # + def voting_open_or_close(program) + return if program.voting_period? + if program.voting_start_date > Date.today + return 'Voting period has not started yet!' + else # voting_end_date > Date.today because voting_start_date < voting_end_date + return 'Voting period is over!' + end + end + ## # Gets an EventType object, and returns its length in timestamp format (HH:MM) # ====Gets @@ -9,6 +21,15 @@ module ApplicationHelper [length / 60, length % 60].map { |t| t.to_s.rjust(2, '0') }.join(':') end + ## + # Gets a datetime object + # ====Returns + # * +String+ -> formated datetime object + def format_datetime(obj) + return unless obj + obj.strftime('%Y-%m-%d %H:%M') + end + ## # ====Returns # * +String+ -> number of registrations / max allowed registrations diff --git a/app/models/event.rb b/app/models/event.rb index 3813c030..0bd224cc 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -82,8 +82,24 @@ class Event < ActiveRecord::Base registrations.count < max_attendees end - def voted?(event, user) - event.votes.where('user_id = ?', user).first + ## + # Finds the rating of the user for the event + # ====Returns + # * +integer+ -> the rating of the user for the event + def user_rating(user) + (vote = votes.find_by(user: user)) ? vote.rating : 0 + end + + ## + # Checks if the event has votes + # If a user is provided, it checks if the event has votes by the user + # ====Returns + # * +true+ -> If the event has votes (optionally, by the user) + # * +false+ -> If the event does not have any votes (optionally, by the user) + def voted?(user=nil) + return votes.where(user: user).any? if user + + votes.any? end def average_rating diff --git a/app/models/program.rb b/app/models/program.rb index ffbb5ef0..b7b82dc2 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -51,12 +51,58 @@ class Program < ActiveRecord::Base accepts_nested_attributes_for :difficulty_levels, allow_destroy: true # validates :conference_id, presence: true, uniqueness: true - validates :rating, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 10 } + 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 before_create :create_event_types before_create :create_difficulty_levels validate :check_languages_format + ## + # 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 + ## # Checcks if the program has rating enabled # diff --git a/app/views/admin/events/_proposal.html.haml b/app/views/admin/events/_proposal.html.haml index 4d8ed950..03b0f07a 100644 --- a/app/views/admin/events/_proposal.html.haml +++ b/app/views/admin/events/_proposal.html.haml @@ -122,10 +122,13 @@ %td %b Submitter %td - = link_to @event.submitter.name, admin_user_path(@event.submitter) - ( - = link_to @event.submitter.email, "mailto: #{@event.submitter.email}" - ) + - if @program.show_voting? + = link_to @event.submitter.name, admin_user_path(@event.submitter) + ( + = link_to @event.submitter.email, "mailto: #{@event.submitter.email}" + ) + - else + %i Hidden %tr %td %b Biography diff --git a/app/views/admin/events/_voting.html.haml b/app/views/admin/events/_voting.html.haml index bc281d87..bae1516e 100644 --- a/app/views/admin/events/_voting.html.haml +++ b/app/views/admin/events/_voting.html.haml @@ -1,54 +1,64 @@ %table.table#myrating + - if @program.show_voting? + %tr + %td.col-md-2 + %b Rating + %td + - if @event.average_rating.to_f > 0 + #{@event.average_rating}/#{@program.rating} + - else + Rating: 0/#{@program.rating} + + - @program.rating.times do |counter| + - if @event.average_rating.to_f.round == counter+1 + = label_tag 'label_rating', '', class: 'avgrating', avgrate: true + = javascript_tag "$('label[avgrate=true]').prevAll().andSelf().addClass('bright');" + - else + = label_tag 'label_rating', '', class: 'avgrating' + %tr + %td + %b Voters + %td + = @event.voters.length + - if @event.voters.length > 0 + ( + = @ratings.map {|x| "#{x.name}"}.join ', ' + ) %tr %td.col-md-2 - %b Rating - %td - - if @event.average_rating.to_f > 0 - #{@event.average_rating}/#{@conference.program.rating} - - else - Rating: 0/#{@conference.program.rating} - - - @conference.program.rating.times do |counter| - - if @event.average_rating.to_f.round == counter+1 - = label_tag "label_rating", "", :class => "avgrating", :avgrate => true - = javascript_tag "$('label[avgrate=true]').prevAll().andSelf().addClass('bright');" - - else - = label_tag "label_rating", "", :class => "avgrating" - %tr - %td - %b Voters - %td - = @event.voters.length - - if @event.voters.length > 0 - ( - = @ratings.map {|x| "#{x.name}"}.join ', ' - ) - %tr - %td %b Your vote %td - - @conference.program.rating.times do |counter| - - voted = @event.voted?(@event, current_user) - - if voted && voted.rating == counter+1 - = link_to "", vote_admin_conference_program_event_path(@conference.short_title, @event, :rating => counter+1), :remote => true, :id =>"label#{counter+1}", :class => "myrating", :voted => true - - else - = link_to "", vote_admin_conference_program_event_path(@conference.short_title, @event, :rating => counter+1), :remote => true, :id =>"label#{counter+1}", :class => "myrating" - %br + - if @program.voting_period? + - @program.rating.times do |counter| + - if @event.voted?(current_user) && @event.user_rating(current_user) == counter+1 + = link_to "", vote_admin_conference_program_event_path(@conference.short_title, @event, :rating => counter+1), :remote => true, :id =>"label#{counter+1}", :class => "myrating", :voted => true + - else + = link_to "", vote_admin_conference_program_event_path(@conference.short_title, @event, :rating => counter+1), :remote => true, :id =>"label#{counter+1}", :class => "myrating" + %br + - else + - @conference.program.rating.times do |counter| + - if @event.voted?(current_user) && @event.user_rating(current_user) == counter+1 + = label_tag "label#{counter+1}", '', class: 'othersrating', voted: true + = javascript_tag "$('label[voted=true]').prevAll().andSelf().addClass('bright');" + - else + = label_tag "label#{counter+1}", '', class: 'othersrating' + (#{voting_open_or_close(@program)}) - - if @ratings.length > 0 - - @ratings.each do |rate| - - unless rate.user_id == current_user.id - %tr - %td - = rate.name - %td - - @conference.program.rating.times do |counter| - - voted = @event.voted?(@event, rate.user) - - if voted && voted.rating == counter+1 - = label_tag "label#{counter+1}", "", :class => "othersrating", :voted => true - = javascript_tag "$('label[voted=true]').prevAll().andSelf().addClass('bright');" - - else - = label_tag "label#{counter+1}", "", :class => "othersrating" + - if @program.show_voting? + - if @ratings.length > 0 + - @ratings.each do |rate| + - unless rate.user_id == current_user.id + %tr + %td + = rate.name + %td + - @conference.program.rating.times do |counter| + + - if @event.voted?(rate.user) && @event.user_rating(rate.user) == counter+1 + = label_tag "label#{counter+1}", "", :class => "othersrating", :voted => true + = javascript_tag "$('label[voted=true]').prevAll().andSelf().addClass('bright');" + - else + = label_tag "label#{counter+1}", "", :class => "othersrating" :javascript $(function () { var checkedId = $("a[voted='true']").attr('id'); diff --git a/app/views/admin/events/_voting_index.html.haml b/app/views/admin/events/_voting_index.html.haml new file mode 100644 index 00000000..96e46fb6 --- /dev/null +++ b/app/views/admin/events/_voting_index.html.haml @@ -0,0 +1,19 @@ +- if @program.show_voting? + #{event.average_rating}/#{@program.rating} + %br + #{pluralize(event.voters.length, 'voter')} + %br + - @program.rating.times do |counter| + - if event.average_rating.to_f.round == counter+1 + = label_tag 'label_rating', '', class: 'avgrating', avgrate: true + = javascript_tag "$('label[avgrate=true]').prevAll().andSelf().addClass('bright');" + - else + = label_tag 'label_rating', '', class: 'avgrating' + %br + +- if event.voted?(current_user) + %span.label.label-success + Your rating: #{ event.user_rating(current_user) } +- else + %span.label.label-danger + Not rated diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml index 83f44eb3..66e1d2f0 100644 --- a/app/views/admin/events/index.html.haml +++ b/app/views/admin/events/index.html.haml @@ -50,49 +50,34 @@ %td = event.id %td - =link_to event.title, admin_conference_program_event_path(@conference.short_title, event) + = link_to event.title, admin_conference_program_event_path(@conference.short_title, event) - if @program.rating_enabled? %td.col-md-1{'data-order' => "#{event.average_rating}"} - - if event.average_rating.to_f > 0 - #{event.average_rating}/#{@program.rating} - %br - #{pluralize(event.voters.length, 'voter')} - %br - - @program.rating.times do |counter| - - if event.average_rating.to_f.round == counter+1 - = label_tag "label_rating", "", :class => "avgrating", :avgrate => true - = javascript_tag "$('label[avgrate=true]').prevAll().andSelf().addClass('bright');" - - else - = label_tag "label_rating", "", :class => "avgrating" - %br - - voted = event.voted?(event, current_user) - - if voted - %span.label.label-success - Your rating: #{voted.rating} - - else - %span.label.label-danger - Not rated - - else - 0/#{@program.rating} - %br + = render partial: 'voting_index', locals: { event: event } - if event.submitter && event.submitter.registrations && event.submitter.registrations.count < 1 - bgcolor="#F7819F" - else - bgcolor="" %td{:style=>"background-color: #{bgcolor}"} - - if !event.submitter.nil? - =link_to event.submitter.name, admin_user_path(event.submitter) - - if event.submitter.registrations.count < 1 - (Unregistered!) + - if @program.show_voting? + - if !event.submitter.nil? + =link_to event.submitter.name, admin_user_path(event.submitter) + - if event.submitter.registrations.count < 1 + (Unregistered!) + - else + Unknown submitter - else - Unknown submitter + %i Hidden %td - - if speaker = event.speakers.first - = link_to speaker.name, admin_user_path(speaker) + - if @program.show_voting? + - if speaker = event.speakers.first + = link_to speaker.name, admin_user_path(speaker) + - else + Unknown speaker - else - Unknown speaker + %i Hidden -if @program.languages.present? %td diff --git a/app/views/admin/programs/_form.html.haml b/app/views/admin/programs/_form.html.haml index e50c8e56..ccf9638f 100644 --- a/app/views/admin/programs/_form.html.haml +++ b/app/views/admin/programs/_form.html.haml @@ -9,5 +9,8 @@ = 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 :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?) } %p.text-right = f.action :submit, as: :button, button_html: {class: 'btn btn-primary'} diff --git a/app/views/admin/programs/show.html.haml b/app/views/admin/programs/show.html.haml index d00d98ca..085a47c1 100644 --- a/app/views/admin/programs/show.html.haml +++ b/app/views/admin/programs/show.html.haml @@ -4,7 +4,7 @@ %h1 Program - if @program .row - .col-md-8 + .col-md-12 %dl.dl-horizontal - if @cfp %dt @@ -49,11 +49,23 @@ Yes - else No + + %h3 Voting Options + %hr %dt Rating Levels %dd#rating = @program.rating + %dt Blind Voting + %dd#blind_voting + = @program.blind_voting + + %dt Voting Start Date + %dd= format_datetime(@program.voting_start_date) + + %dt Voting End Date + %dd= format_datetime(@program.voting_end_date) .row .col-md-12.text-right diff --git a/db/migrate/20160427104237_add_blind_voting_to_programs.rb b/db/migrate/20160427104237_add_blind_voting_to_programs.rb new file mode 100644 index 00000000..0313cf19 --- /dev/null +++ b/db/migrate/20160427104237_add_blind_voting_to_programs.rb @@ -0,0 +1,5 @@ +class AddBlindVotingToPrograms < ActiveRecord::Migration + def change + add_column :programs, :blind_voting, :boolean, default: false + end +end diff --git a/db/migrate/20160427104238_add_voting_dates_to_program.rb b/db/migrate/20160427104238_add_voting_dates_to_program.rb new file mode 100644 index 00000000..9dcbf752 --- /dev/null +++ b/db/migrate/20160427104238_add_voting_dates_to_program.rb @@ -0,0 +1,6 @@ +class AddVotingDatesToProgram < ActiveRecord::Migration + def change + add_column :programs, :voting_start_date, :datetime + add_column :programs, :voting_end_date, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index aa8021c8..120ea7e5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -80,23 +80,23 @@ ActiveRecord::Schema.define(version: 20160624151257) do end create_table "conferences", force: :cascade do |t| - t.string "guid", null: false - t.string "title", null: false - t.string "short_title", null: false - t.string "timezone", null: false - t.date "start_date", null: false - t.date "end_date", null: false + t.string "guid", null: false + t.string "title", null: false + t.string "short_title", null: false + t.string "timezone", null: false + t.date "start_date", null: false + t.date "end_date", null: false t.datetime "created_at" t.datetime "updated_at" t.string "logo_file_name" t.integer "revision" - t.boolean "use_vpositions", default: false - t.boolean "use_vdays", default: false + t.boolean "use_vpositions", default: false + t.boolean "use_vdays", default: false t.boolean "use_volunteers" t.string "color" t.text "events_per_week" t.text "description" - t.integer "registration_limit", default: 0 + t.integer "registration_limit", default: 0 t.string "picture" end @@ -252,12 +252,15 @@ 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.datetime "voting_start_date" + t.datetime "voting_end_date" end create_table "qanswers", force: :cascade do |t| diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 8359506d..89a44ea2 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -4,6 +4,17 @@ describe ApplicationHelper, type: :helper do let(:conference) { create(:conference) } let(:event) { create(:event, program: conference.program) } + describe 'format_datetme' do + it 'returns nothing if there is no parameter' do + expect(format_datetime(nil)).to eq nil + end + + it 'returns formatted string' do + datetime = Time.zone.local(2016, 05, 04, 11, 30) + expect(format_datetime(datetime)).to eq '2016-05-04 11:30' + end + end + describe 'show_roles' do it 'formats the hash passed' do roles = { 'organizer' => ['oSC16', 'oSC15'], 'cfp' => ['oSC16'] } diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index b3f9a477..c9cd64d3 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -6,6 +6,7 @@ describe Event do let(:event) { create(:event, program: conference.program) } let(:new_event) { create(:event) } let(:user) { create(:user) } + let(:another_user) { create(:user) } describe 'association' do it { is_expected.to belong_to :program } @@ -166,14 +167,41 @@ describe Event do end end - describe '#voted?' do - it 'returns nil if the event has no votes' do - expect(event.voted?(event, user)).to eq nil + describe '#user_rating' do + it 'returns 0 if the event has no votes' do + expect(event.user_rating(user)).to eq 0 end - it 'returns the first vote when the event has votes' do - vote = create(:vote, user: user, event: event) - expect(event.voted?(event, user)).to eq vote + it 'returns 0 if the event has no votes from that user' do + create(:vote, user: another_user, event: event) + expect(event.user_rating(user)).to eq 0 + end + + it 'returns the rating if the event has votes from that user' do + create(:vote, user: another_user, event: event, rating: 3) + create(:vote, user: user, event: event, rating: 2) + expect(event.user_rating(user)).to eq 2 + end + end + + describe '#voted?' do + it 'returns false if the event has no votes' do + expect(event.voted?).to eq false + end + + it 'returns false if the event has no votes by that user' do + create(:vote, user: another_user, event: event) + expect(event.voted?(user)).to eq false + end + + it 'returns true when the event has votes' do + create(:vote, user: another_user, event: event) + expect(event.voted?).to eq true + end + + it 'returns true when the event has votes by that user' do + create(:vote, user: user, event: event) + expect(event.voted?(user)).to eq true end end diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index 9b7883bd..d9c7590d 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -1,9 +1,116 @@ require 'spec_helper' describe Program do + subject { create(:program) } let!(:conference) { create(:conference, end_date: Date.today + 3) } let!(:program) { conference.program } + 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(:event_types).dependent(:destroy) } + 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_users).through(:events) } + it { is_expected.to have_many(:speakers).through(:event_users).source(:user) } + + it { is_expected.to accept_nested_attributes_for(:event_types) } + it { is_expected.to accept_nested_attributes_for(:tracks) } + it { is_expected.to accept_nested_attributes_for(:difficulty_levels) } + end + + describe 'validation' do + it 'has a valid factory' do + expect(build(:program)).to be_valid + end + + it 'is valid for rating of 5' do + expect(build(:program, rating: 5)).to be_valid + end + + it { is_expected.to validate_numericality_of(:rating).is_greater_than_or_equal_to(0).is_less_than_or_equal_to(10).only_integer } + + 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 + end + + it 'is valid, when voting_start_date is before voting_end_date' do + expect(build(:program, voting_start_date: Date.today, voting_end_date: Date.today + 1)).to be_valid + end + + it 'is not valid, when voting_start_date is after voting_end_date' do + expect(build(:program, voting_start_date: Date.today, voting_end_date: Date.today - 1)).to_not be_valid + end + end + + describe 'voting_dates_exist' do + it 'is valid, when both voting_start_date and voting_end_date are set' do + expect(build(:program, voting_start_date: Date.today, voting_end_date: Date.today + 1)).to be_valid + end + + it 'is invalid, when voting_start_date is not set' do + expect(build(:program, voting_end_date: Date.today)).to_not be_valid + end + + it 'is invalid, when voting_end_date is not set' do + expect(build(:program, voting_start_date: Date.today)).to_not be_valid + end + end + end + + describe '#show_voting?' do + context 'blind voting is disabled' do + before :each do + program.blind_voting = false + end + it 'returns true if blind_voting is disabled' do + program.blind_voting = false + expect(program.show_voting?).to eq true + end + end + + context 'blind voting is enabled' do + before :each do + program.blind_voting = true + end + + it 'returns true if voting period is over' do + program.voting_end_date = Date.today - 1 + expect(program.show_voting?).to eq true + end + + it 'returns false if we are still in votig period' do + program.voting_end_date = Date.today + 1 + expect(program.show_voting?).to eq false + end + end + end + + describe 'voting_period?' do + it 'retuns false when voting dates are not set' do + expect(program.voting_period?).to eq false + end + + shared_examples 'voting period' do |voting_start_date, voting_end_date, returns| + scenario 'returns true or false' do + program.voting_start_date = voting_start_date + program.voting_end_date = voting_end_date + program.save! + + expect(program.voting_period?).to eq returns + end + end + + context 'voting dates are set' do + it_behaves_like 'voting period', Date.today - 1, Date.today + 1, true + it_behaves_like 'voting period', Date.today - 1, Time.current + 1.hour, true + it_behaves_like 'voting period', Date.today - 2, Date.today - 1, false + it_behaves_like 'voting period', Date.today - 1, Time.current - 1.minute, false + end + end + describe '#rating_enabled?' do it 'returns true if proposals can be rated (program.rating > 0)' do program.rating = 3