diff --git a/app/assets/javascripts/datepicker.js b/app/assets/javascripts/datepicker.js index 1e483ea6a..eab188097 100644 --- a/app/assets/javascripts/datepicker.js +++ b/app/assets/javascripts/datepicker.js @@ -23,6 +23,16 @@ }); $(".js-calendar-full").datepicker(); + if (!App.Datepicker.browser_supports_datetime_local_field()) { + if (App.Datepicker.browser_supports_date_field()) { + $("input[type='datetime-local']").prop("type", "text") + .val(App.Datepicker.datetime_to_date) + .prop("type", "date"); + } else { + $("input[type='datetime-local']").val(App.Datepicker.datetime_to_date).datepicker(); + } + } + if (!App.Datepicker.browser_supports_date_field()) { $("input[type='date']").datepicker(); } @@ -39,11 +49,20 @@ }); }, browser_supports_date_field: function() { - var datefield; + return App.Datepicker.browser_supports_field_with_type("date"); + }, + browser_supports_datetime_local_field: function() { + return App.Datepicker.browser_supports_field_with_type("datetime-local"); + }, + browser_supports_field_with_type: function(field_type) { + var field; - datefield = document.createElement("input"); - datefield.setAttribute("type", "date"); - return datefield.type === "date"; + field = document.createElement("input"); + field.setAttribute("type", field_type); + return field.type === field_type; + }, + datetime_to_date: function(index, value) { + return value.split("T")[0]; } }; diff --git a/app/models/poll.rb b/app/models/poll.rb index dcc081168..2acd9cfb0 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -42,9 +42,9 @@ class Poll < ApplicationRecord accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true scope :for, ->(element) { where(related: element) } - scope :current, -> { where("starts_at <= :time and ends_at >= :time", time: Date.current.beginning_of_day) } - scope :expired, -> { where("ends_at < ?", Date.current.beginning_of_day) } - scope :recounting, -> { where(ends_at: (Date.current.beginning_of_day - RECOUNT_DURATION)...Date.current.beginning_of_day) } + scope :current, -> { where("starts_at <= :time and ends_at >= :time", time: Time.current) } + scope :expired, -> { where("ends_at < ?", Time.current) } + scope :recounting, -> { where(ends_at: (RECOUNT_DURATION.ago)...Time.current) } scope :published, -> { where(published: true) } scope :by_geozone_id, ->(geozone_id) { where(geozones: { id: geozone_id }.joins(:geozones)) } scope :public_for_api, -> { all } @@ -67,11 +67,11 @@ class Poll < ApplicationRecord name end - def current?(timestamp = Date.current.beginning_of_day) + def current?(timestamp = Time.current) starts_at <= timestamp && timestamp <= ends_at end - def expired?(timestamp = Date.current.beginning_of_day) + def expired?(timestamp = Time.current) ends_at < timestamp end diff --git a/app/views/admin/poll/polls/_form.html.erb b/app/views/admin/poll/polls/_form.html.erb index 926a98ce4..dd0b59292 100644 --- a/app/views/admin/poll/polls/_form.html.erb +++ b/app/views/admin/poll/polls/_form.html.erb @@ -6,11 +6,11 @@
- <%= f.date_field :starts_at %> + <%= f.datetime_field :starts_at %>
- <%= f.date_field :ends_at %> + <%= f.datetime_field :ends_at %>
diff --git a/app/views/admin/poll/polls/_poll.html.erb b/app/views/admin/poll/polls/_poll.html.erb index 8f477c586..80b64d43c 100644 --- a/app/views/admin/poll/polls/_poll.html.erb +++ b/app/views/admin/poll/polls/_poll.html.erb @@ -1,7 +1,7 @@ <%= poll.name %> - <%= l poll.starts_at.beginning_of_day, format: :short_datetime %> - <%= l poll.ends_at.end_of_day, format: :short_datetime %> + <%= l poll.starts_at, format: :short_datetime %> + <%= l poll.ends_at, format: :short_datetime %> <% if feature?(:sdg) %> <%= poll.sdg_goal_list %> <%= poll.sdg_target_list %> diff --git a/app/views/admin/poll/polls/_poll_header.html.erb b/app/views/admin/poll/polls/_poll_header.html.erb index ef24e0e0c..c6dcd0e7c 100644 --- a/app/views/admin/poll/polls/_poll_header.html.erb +++ b/app/views/admin/poll/polls/_poll_header.html.erb @@ -12,7 +12,7 @@
<%= t("admin.polls.index.dates") %>
- <%= render Admin::DateRangeComponent.new(@poll.starts_at.beginning_of_day, @poll.ends_at.end_of_day) %> + <%= render Admin::DurationComponent.new(@poll) %>
<% if @poll.geozone_restricted %> diff --git a/lib/tasks/consul.rake b/lib/tasks/consul.rake index f1074d23e..97bfb0365 100644 --- a/lib/tasks/consul.rake +++ b/lib/tasks/consul.rake @@ -11,6 +11,7 @@ namespace :consul do desc "Runs tasks needed to upgrade from 1.5.0 to 1.6.0" task "execute_release_1.6.0_tasks": [ - "db:calculate_tsv" + "db:calculate_tsv", + "polls:set_ends_at_to_end_of_day" ] end diff --git a/lib/tasks/polls.rake b/lib/tasks/polls.rake new file mode 100644 index 000000000..d909650f1 --- /dev/null +++ b/lib/tasks/polls.rake @@ -0,0 +1,10 @@ +namespace :polls do + desc "Changes the polls ending date to the end of the day" + task set_ends_at_to_end_of_day: :environment do + ApplicationLogger.new.info "Adding time to the date where a poll ends" + + Poll.find_each do |poll| + poll.update_column :ends_at, poll.ends_at.end_of_day.beginning_of_minute + end + end +end diff --git a/spec/lib/tasks/polls_spec.rb b/spec/lib/tasks/polls_spec.rb new file mode 100644 index 000000000..e30e91a71 --- /dev/null +++ b/spec/lib/tasks/polls_spec.rb @@ -0,0 +1,23 @@ +require "rails_helper" + +describe "rake polls:set_ends_at_to_end_of_day" do + before { Rake::Task["polls:set_ends_at_to_end_of_day"].reenable } + + let :run_rake_task do + Rake.application.invoke_task("polls:set_ends_at_to_end_of_day") + end + + it "updates existing polls" do + travel_to(Time.zone.local(2015, 7, 15, 13, 32, 13)) + poll = create(:poll, ends_at: 2.years.from_now) + date_poll = create(:poll, ends_at: 3.years.from_now.to_date) + + expect(I18n.l(poll.reload.ends_at, format: :datetime)).to eq "2017-07-15 13:32:13" + expect(I18n.l(date_poll.reload.ends_at, format: :datetime)).to eq "2018-07-15 00:00:00" + + run_rake_task + + expect(I18n.l(poll.reload.ends_at, format: :datetime)).to eq "2017-07-15 23:59:00" + expect(I18n.l(date_poll.reload.ends_at, format: :datetime)).to eq "2018-07-15 23:59:00" + end +end diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index a2b94d729..751f4a85a 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -86,12 +86,12 @@ describe Poll do end end - describe "#current?" do + describe "#current?", :with_frozen_time do it "returns true only when it isn't too late" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - just_started = create(:poll, starts_at: Date.current) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + just_started = create(:poll, starts_at: Time.current) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) expect(just_started).to be_current expect(about_to_end).to be_current @@ -100,11 +100,11 @@ describe Poll do end end - describe "#expired?" do + describe "#expired?", :with_frozen_time do it "returns true only when it is too late" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) recounting_ended = create(:poll, starts_at: 3.years.ago, ends_at: 2.years.ago) expect(just_ended).to be_expired @@ -325,12 +325,12 @@ describe Poll do end describe "scopes" do - describe ".current" do + describe ".current", :with_frozen_time do it "returns polls which have started but not ended" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - just_started = create(:poll, starts_at: Date.current) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + just_started = create(:poll, starts_at: Time.current) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) current_polls = Poll.current @@ -340,11 +340,11 @@ describe Poll do end end - describe ".expired" do + describe ".expired", :with_frozen_time do it "returns polls which have already ended" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) recounting_ended = create(:poll, starts_at: 3.years.ago, ends_at: 2.years.ago) expired_polls = Poll.expired @@ -355,11 +355,11 @@ describe Poll do end end - describe ".recounting" do + describe ".recounting", :with_frozen_time do it "returns polls in recount & scrutiny phase" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) recounting_ended = create(:poll, starts_at: 3.years.ago, ends_at: 2.years.ago) recounting_polls = Poll.recounting @@ -371,12 +371,12 @@ describe Poll do end end - describe ".current_or_recounting" do + describe ".current_or_recounting", :with_frozen_time do it "returns current or recounting polls" do - about_to_start = create(:poll, starts_at: Date.tomorrow) - just_started = create(:poll, starts_at: Date.current) - about_to_end = create(:poll, ends_at: Date.current) - just_ended = create(:poll, ends_at: Date.yesterday) + about_to_start = create(:poll, starts_at: 1.second.from_now) + just_started = create(:poll, starts_at: Time.current) + about_to_end = create(:poll, ends_at: Time.current) + just_ended = create(:poll, ends_at: 1.second.ago) recounting_ended = create(:poll, starts_at: 3.years.ago, ends_at: 2.years.ago) current_or_recounting = Poll.current_or_recounting @@ -474,7 +474,7 @@ describe Poll do end it "is false for recounting polls" do - poll = create(:poll, ends_at: Date.yesterday) + poll = create(:poll, ends_at: 1.second.ago) expect(poll.recounts_confirmed?).to be false end diff --git a/spec/system/admin/poll/polls_spec.rb b/spec/system/admin/poll/polls_spec.rb index 7bd857ecc..23f023e1f 100644 --- a/spec/system/admin/poll/polls_spec.rb +++ b/spec/system/admin/poll/polls_spec.rb @@ -47,15 +47,14 @@ describe "Admin polls", :admin do end scenario "Create" do + travel_to(Time.zone.local(2015, 7, 15, 13, 32, 13)) + visit admin_polls_path click_link "Create poll" - start_date = 1.week.from_now.to_date - end_date = 2.weeks.from_now.to_date - fill_in "Name", with: "Upcoming poll" - fill_in "poll_starts_at", with: start_date - fill_in "poll_ends_at", with: end_date + fill_in "Start Date", with: 1.week.from_now + fill_in "Closing Date", with: 2.weeks.from_now fill_in "Summary", with: "Upcoming poll's summary. This poll..." fill_in "Description", with: "Upcomming poll's description. This poll..." @@ -67,8 +66,8 @@ describe "Admin polls", :admin do expect(page).to have_content "Poll created successfully" expect(page).to have_content "Upcoming poll" - expect(page).to have_content "#{I18n.l(start_date)} 00:00" - expect(page).to have_content "#{I18n.l(end_date)} 23:59" + expect(page).to have_content "2015-07-22 13:32" + expect(page).to have_content "2015-07-29 13:32" visit poll_path(id: "upcoming-poll") @@ -76,24 +75,23 @@ describe "Admin polls", :admin do end scenario "Edit" do - poll = create(:poll, :with_image) + travel_to(Time.zone.local(2015, 7, 15, 13, 32, 13)) + poll = create(:poll, :with_image, ends_at: 1.month.from_now.beginning_of_minute) visit admin_poll_path(poll) click_link "Edit poll" - end_date = 1.year.from_now.to_date - expect(page).to have_css("img[alt='#{poll.image.title}']") expect(page).to have_link "Go back", href: admin_polls_path fill_in "Name", with: "Next Poll" - fill_in "poll_ends_at", with: end_date + fill_in "Closing Date", with: 1.year.from_now click_button "Update poll" expect(page).to have_content "Poll updated successfully" expect(page).to have_content "Next Poll" - expect(page).to have_content "#{I18n.l(end_date)} 23:59" + expect(page).to have_content "2016-07-15 13:32" end scenario "Edit from index" do diff --git a/spec/system/budget_polls/budgets_spec.rb b/spec/system/budget_polls/budgets_spec.rb index 6a4f1c56b..bbd8ea26a 100644 --- a/spec/system/budget_polls/budgets_spec.rb +++ b/spec/system/budget_polls/budgets_spec.rb @@ -13,7 +13,7 @@ describe "Admin Budgets", :admin do expect(page).to have_current_path(/admin\/polls\/\d+/) expect(page).to have_content(budget.name) expect(page).to have_content("#{balloting_phase.starts_at.to_date} 00:00") - expect(page).to have_content("#{balloting_phase.ends_at.to_date} 23:59") + expect(page).to have_content("#{balloting_phase.ends_at.to_date - 1.day} 23:59") end scenario "Create poll in current locale if the budget does not have a poll associated" do