Allow only creation of polls with dates that are not in the past

This commit is contained in:
Julian Herrero
2022-09-14 16:16:49 +02:00
committed by Javi Martín
parent 05dbae5a3c
commit 855fedc025
6 changed files with 64 additions and 7 deletions

View File

@@ -37,6 +37,8 @@ class Poll < ApplicationRecord
validates_translation :name, presence: true validates_translation :name, presence: true
validate :date_range validate :date_range
validate :start_date_is_not_past_date, on: :create
validate :start_date_change, on: :update
validate :only_one_active, unless: :public? validate :only_one_active, unless: :public?
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
@@ -143,6 +145,18 @@ class Poll < ApplicationRecord
end end
end end
def start_date_is_not_past_date
if starts_at.present? && starts_at < Time.current
errors.add(:starts_at, I18n.t("errors.messages.past_date"))
end
end
def start_date_change
if will_save_change_to_starts_at? && starts_at < Time.current
errors.add(:starts_at, I18n.t("errors.messages.past_date"))
end
end
def generate_slug? def generate_slug?
slug.nil? slug.nil?
end end

View File

@@ -137,6 +137,7 @@ en:
allowed_file_content_types: "content type must be one of %{types}" allowed_file_content_types: "content type must be one of %{types}"
user_not_found: User not found user_not_found: User not found
invalid_date_range: "Invalid date range" invalid_date_range: "Invalid date range"
past_date: "Must not be a past date"
form: form:
accept_terms: I agree to the %{policy} and the %{conditions} accept_terms: I agree to the %{policy} and the %{conditions}
accept_terms_title: I agree to the Privacy Policy and the Terms and conditions of use accept_terms_title: I agree to the Privacy Policy and the Terms and conditions of use

View File

@@ -137,6 +137,7 @@ es:
allowed_file_content_types: "el tipo de contenido debe ser uno de los siguientes: %{types}" allowed_file_content_types: "el tipo de contenido debe ser uno de los siguientes: %{types}"
user_not_found: Usuario no encontrado user_not_found: Usuario no encontrado
invalid_date_range: "El rango de fechas no es válido" invalid_date_range: "El rango de fechas no es válido"
past_date: "No puede ser una fecha pasada"
form: form:
accept_terms: Acepto la %{policy} y las %{conditions} accept_terms: Acepto la %{policy} y las %{conditions}
accept_terms_title: Acepto la Política de privacidad y las Condiciones de uso accept_terms_title: Acepto la Política de privacidad y las Condiciones de uso

View File

@@ -2,30 +2,38 @@ require_dependency "poll/answer"
require_dependency "poll/question/answer" require_dependency "poll/question/answer"
section "Creating polls" do section "Creating polls" do
Poll.create!(name: I18n.t("seeds.polls.current_poll"), def create_poll!(attributes)
poll = Poll.create!(attributes.merge(starts_at: 1.day.from_now, ends_at: 2.days.from_now))
poll.update_columns(
starts_at: attributes[:starts_at].beginning_of_minute,
ends_at: attributes[:ends_at].beginning_of_minute
)
end
create_poll!(name: I18n.t("seeds.polls.current_poll"),
slug: I18n.t("seeds.polls.current_poll").parameterize, slug: I18n.t("seeds.polls.current_poll").parameterize,
starts_at: 7.days.ago, starts_at: 7.days.ago,
ends_at: 7.days.from_now, ends_at: 7.days.from_now,
geozone_restricted: false) geozone_restricted: false)
Poll.create!(name: I18n.t("seeds.polls.current_poll_geozone_restricted"), create_poll!(name: I18n.t("seeds.polls.current_poll_geozone_restricted"),
slug: I18n.t("seeds.polls.current_poll_geozone_restricted").parameterize, slug: I18n.t("seeds.polls.current_poll_geozone_restricted").parameterize,
starts_at: 5.days.ago, starts_at: 5.days.ago,
ends_at: 5.days.from_now, ends_at: 5.days.from_now,
geozone_restricted: true, geozone_restricted: true,
geozones: Geozone.sample(3)) geozones: Geozone.sample(3))
Poll.create!(name: I18n.t("seeds.polls.recounting_poll"), create_poll!(name: I18n.t("seeds.polls.recounting_poll"),
slug: I18n.t("seeds.polls.recounting_poll").parameterize, slug: I18n.t("seeds.polls.recounting_poll").parameterize,
starts_at: 15.days.ago, starts_at: 15.days.ago,
ends_at: 2.days.ago) ends_at: 2.days.ago)
Poll.create!(name: I18n.t("seeds.polls.expired_poll_without_stats"), create_poll!(name: I18n.t("seeds.polls.expired_poll_without_stats"),
slug: I18n.t("seeds.polls.expired_poll_without_stats").parameterize, slug: I18n.t("seeds.polls.expired_poll_without_stats").parameterize,
starts_at: 2.months.ago, starts_at: 2.months.ago,
ends_at: 1.month.ago) ends_at: 1.month.ago)
Poll.create!(name: I18n.t("seeds.polls.expired_poll_with_stats"), create_poll!(name: I18n.t("seeds.polls.expired_poll_with_stats"),
slug: I18n.t("seeds.polls.expired_poll_with_stats").parameterize, slug: I18n.t("seeds.polls.expired_poll_with_stats").parameterize,
starts_at: 2.months.ago, starts_at: 2.months.ago,
ends_at: 1.month.ago, ends_at: 1.month.ago,

View File

@@ -6,6 +6,7 @@ FactoryBot.define do
starts_at { 1.month.ago } starts_at { 1.month.ago }
ends_at { 1.month.from_now } ends_at { 1.month.from_now }
to_create { |poll| poll.save(validate: false) }
trait :expired do trait :expired do
starts_at { 1.month.ago } starts_at { 1.month.ago }
@@ -17,6 +18,10 @@ FactoryBot.define do
ends_at { 2.months.ago } ends_at { 2.months.ago }
end end
trait :future do
starts_at { 1.day.from_now }
end
trait :published do trait :published do
published { true } published { true }
end end

View File

@@ -1,7 +1,7 @@
require "rails_helper" require "rails_helper"
describe Poll do describe Poll do
let(:poll) { build(:poll) } let(:poll) { build(:poll, :future) }
describe "Concerns" do describe "Concerns" do
it_behaves_like "notifiable" it_behaves_like "notifiable"
@@ -22,7 +22,9 @@ describe Poll do
it "is not valid without a start date" do it "is not valid without a start date" do
poll.starts_at = nil poll.starts_at = nil
expect(poll).not_to be_valid expect(poll).not_to be_valid
expect(poll.errors[:starts_at]).to eq ["Invalid date range"]
end end
it "is not valid without an end date" do it "is not valid without an end date" do
@@ -35,11 +37,37 @@ describe Poll do
poll.ends_at = 2.months.ago poll.ends_at = 2.months.ago
expect(poll).not_to be_valid expect(poll).not_to be_valid
end end
it "is valid if start date is greater than current time" do
poll.starts_at = 1.minute.from_now
expect(poll).to be_valid
end
it "is not valid if start date is a past date" do
poll.starts_at = 1.minute.ago
expect(poll).not_to be_valid
expect(poll.errors[:starts_at]).to eq ["Must not be a past date"]
end
context "persisted poll" do
let(:poll) { create(:poll, :future) }
it "is valid if the start date changes to a future date" do
poll.starts_at = 1.minute.from_now
expect(poll).to be_valid
end
it "is not valid if the start date changes to a past date" do
poll.starts_at = 1.minute.ago
expect(poll).not_to be_valid
end
end
end end
describe "proposal polls specific validations" do describe "proposal polls specific validations" do
let(:proposal) { create(:proposal) } let(:proposal) { create(:proposal) }
let(:poll) { build(:poll, related: proposal) } let(:poll) { build(:poll, :future, related: proposal) }
it "is valid when overlapping but different proposals" do it "is valid when overlapping but different proposals" do
other_proposal = create(:proposal) other_proposal = create(:proposal)