mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
REFACTOR: use tables instead of custom fields for polls (#6359)
Co-authored-by: Guo Xiang Tan <tgx_world@hotmail.com>
This commit is contained in:
76
plugins/poll/app/models/poll.rb
Normal file
76
plugins/poll/app/models/poll.rb
Normal file
@@ -0,0 +1,76 @@
|
||||
class Poll < ActiveRecord::Base
|
||||
# because we want to use the 'type' column and don't want to use STI
|
||||
self.inheritance_column = nil
|
||||
|
||||
belongs_to :post
|
||||
|
||||
has_many :poll_options, dependent: :destroy
|
||||
has_many :poll_votes
|
||||
|
||||
enum type: {
|
||||
regular: 0,
|
||||
multiple: 1,
|
||||
number: 2,
|
||||
}
|
||||
|
||||
enum status: {
|
||||
open: 0,
|
||||
closed: 1,
|
||||
}
|
||||
|
||||
enum results: {
|
||||
always: 0,
|
||||
on_vote: 1,
|
||||
on_close: 2,
|
||||
}
|
||||
|
||||
enum visibility: {
|
||||
secret: 0,
|
||||
everyone: 1,
|
||||
}
|
||||
|
||||
validates :min, numericality: { allow_nil: true, only_integer: true, greater_than: 0 }
|
||||
validates :max, numericality: { allow_nil: true, only_integer: true, greater_than: 0 }
|
||||
validates :step, numericality: { allow_nil: true, only_integer: true, greater_than: 0 }
|
||||
|
||||
def is_closed?
|
||||
closed? || (close_at && close_at <= Time.zone.now)
|
||||
end
|
||||
|
||||
def can_see_results?(user)
|
||||
always? || is_closed? || (on_vote? && has_voted?(user))
|
||||
end
|
||||
|
||||
def has_voted?(user)
|
||||
user&.id && poll_votes.any? { |v| v.user_id == user.id }
|
||||
end
|
||||
|
||||
def can_see_voters?(user)
|
||||
everyone? && can_see_results?(user)
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: polls
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# post_id :bigint(8)
|
||||
# name :string default("poll"), not null
|
||||
# close_at :datetime
|
||||
# type :integer default("regular"), not null
|
||||
# status :integer default("open"), not null
|
||||
# results :integer default("always"), not null
|
||||
# visibility :integer default("secret"), not null
|
||||
# min :integer
|
||||
# max :integer
|
||||
# step :integer
|
||||
# anonymous_voters :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_polls_on_post_id (post_id)
|
||||
# index_polls_on_post_id_and_name (post_id,name) UNIQUE
|
||||
#
|
||||
24
plugins/poll/app/models/poll_option.rb
Normal file
24
plugins/poll/app/models/poll_option.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class PollOption < ActiveRecord::Base
|
||||
belongs_to :poll
|
||||
has_many :poll_votes, dependent: :delete_all
|
||||
|
||||
default_scope { order(created_at: :asc) }
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: poll_options
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# poll_id :bigint(8)
|
||||
# digest :string not null
|
||||
# html :text not null
|
||||
# anonymous_votes :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_poll_options_on_poll_id (poll_id)
|
||||
# index_poll_options_on_poll_id_and_digest (poll_id,digest) UNIQUE
|
||||
#
|
||||
23
plugins/poll/app/models/poll_vote.rb
Normal file
23
plugins/poll/app/models/poll_vote.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class PollVote < ActiveRecord::Base
|
||||
belongs_to :poll
|
||||
belongs_to :poll_option
|
||||
belongs_to :user
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: poll_votes
|
||||
#
|
||||
# poll_id :bigint(8)
|
||||
# poll_option_id :bigint(8)
|
||||
# user_id :bigint(8)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_poll_votes_on_poll_id (poll_id)
|
||||
# index_poll_votes_on_poll_id_and_poll_option_id_and_user_id (poll_id,poll_option_id,user_id) UNIQUE
|
||||
# index_poll_votes_on_poll_option_id (poll_option_id)
|
||||
# index_poll_votes_on_user_id (user_id)
|
||||
#
|
||||
14
plugins/poll/app/serializers/poll_option_serializer.rb
Normal file
14
plugins/poll/app/serializers/poll_option_serializer.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
class PollOptionSerializer < ApplicationSerializer
|
||||
|
||||
attributes :id, :html, :votes
|
||||
|
||||
def id
|
||||
object.digest
|
||||
end
|
||||
|
||||
def votes
|
||||
# `size` instead of `count` to prevent N+1
|
||||
object.poll_votes.size + object.anonymous_votes.to_i
|
||||
end
|
||||
|
||||
end
|
||||
50
plugins/poll/app/serializers/poll_serializer.rb
Normal file
50
plugins/poll/app/serializers/poll_serializer.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
class PollSerializer < ApplicationSerializer
|
||||
attributes :name,
|
||||
:type,
|
||||
:status,
|
||||
:public,
|
||||
:results,
|
||||
:min,
|
||||
:max,
|
||||
:step,
|
||||
:options,
|
||||
:voters,
|
||||
:close
|
||||
|
||||
def public
|
||||
true
|
||||
end
|
||||
|
||||
def include_public?
|
||||
object.everyone?
|
||||
end
|
||||
|
||||
def include_min?
|
||||
object.min.present? && (object.number? || object.multiple?)
|
||||
end
|
||||
|
||||
def include_max?
|
||||
object.max.present? && (object.number? || object.multiple?)
|
||||
end
|
||||
|
||||
def include_step?
|
||||
object.step.present? && object.number?
|
||||
end
|
||||
|
||||
def options
|
||||
object.poll_options.map { |o| PollOptionSerializer.new(o, root: false).as_json }
|
||||
end
|
||||
|
||||
def voters
|
||||
object.poll_votes.map { |v| v.user_id }.uniq.count + object.anonymous_voters.to_i
|
||||
end
|
||||
|
||||
def close
|
||||
object.close_at
|
||||
end
|
||||
|
||||
def include_close?
|
||||
object.close_at.present?
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user