discourse/plugins/poll/lib/polls_validator.rb
Guo Xiang Tan a849fae5ee Add specs for polls (#4246)
* Extract validation logic into a service object.

* Extract logic for updating polls custom fields into a service object.

* Use `strip_heredoc` instead.

* FIX: Polls do not update when configuration has been changed.
2016-06-06 17:04:56 +02:00

112 lines
3.2 KiB
Ruby

module DiscoursePoll
class PollsValidator
def initialize(post)
@post = post
end
def validate_polls
polls = {}
extracted_polls = DiscoursePoll::Poll::extract(@post.raw, @post.topic_id)
extracted_polls.each do |poll|
# polls should have a unique name
return false unless unique_poll_name?(polls, poll)
# options must be unique
return false unless unique_options?(poll)
# at least 2 options
return false unless at_least_two_options?(poll)
# maximum # of options
return false unless valid_number_of_options?(poll)
# poll with multiple choices
return false unless valid_multiple_choice_settings?(poll)
# store the valid poll
polls[poll["name"]] = poll
end
polls
end
private
def unique_poll_name?(polls, poll)
if polls.has_key?(poll["name"])
if poll["name"] == ::DiscoursePoll::DEFAULT_POLL_NAME
@post.errors.add(:base, I18n.t("poll.multiple_polls_without_name"))
else
@post.errors.add(:base, I18n.t("poll.multiple_polls_with_same_name", name: poll["name"]))
end
return false
end
true
end
def unique_options?(poll)
if poll["options"].map { |o| o["id"] }.uniq.size != poll["options"].size
if poll["name"] == ::DiscoursePoll::DEFAULT_POLL_NAME
@post.errors.add(:base, I18n.t("poll.default_poll_must_have_different_options"))
else
@post.errors.add(:base, I18n.t("poll.named_poll_must_have_different_options", name: poll["name"]))
end
return false
end
true
end
def at_least_two_options?(poll)
if poll["options"].size < 2
if poll["name"] == ::DiscoursePoll::DEFAULT_POLL_NAME
@post.errors.add(:base, I18n.t("poll.default_poll_must_have_at_least_2_options"))
else
@post.errors.add(:base, I18n.t("poll.named_poll_must_have_at_least_2_options", name: poll["name"]))
end
return false
end
true
end
def valid_number_of_options?(poll)
if poll["options"].size > SiteSetting.poll_maximum_options
if poll["name"] == ::DiscoursePoll::DEFAULT_POLL_NAME
@post.errors.add(:base, I18n.t("poll.default_poll_must_have_less_options", count: SiteSetting.poll_maximum_options))
else
@post.errors.add(:base, I18n.t("poll.named_poll_must_have_less_options", name: poll["name"], count: SiteSetting.poll_maximum_options))
end
return false
end
true
end
def valid_multiple_choice_settings?(poll)
if poll["type"] == "multiple"
min = (poll["min"].presence || 1).to_i
max = (poll["max"].presence || poll["options"].size).to_i
if min > max || max <= 0 || max > poll["options"].size || min >= poll["options"].size
if poll["name"] == ::DiscoursePoll::DEFAULT_POLL_NAME
@post.errors.add(:base, I18n.t("poll.default_poll_with_multiple_choices_has_invalid_parameters"))
else
@post.errors.add(:base, I18n.t("poll.named_poll_with_multiple_choices_has_invalid_parameters", name: poll["name"]))
end
return false
end
end
true
end
end
end