Add voters count support (#11917)

* Add voters count to polls

* Add ActivityPub serialization and parsing of voters count

* Add support for voters count in WebUI

* Move incrementation of voters count out of redis lock

* Reword “voters” to “people”
This commit is contained in:
ThibG 2019-09-29 22:58:01 +02:00 committed by Eugen Rochko
parent cfe2d1cc4a
commit 3babf8464b
13 changed files with 113 additions and 20 deletions

View file

@ -28,6 +28,8 @@ class ActivityPub::ProcessPollService < BaseService
end
end
voters_count = @json['votersCount']
latest_options = items.map { |item| item['name'].presence || item['content'] }
# If for some reasons the options were changed, it invalidates all previous
@ -39,7 +41,8 @@ class ActivityPub::ProcessPollService < BaseService
last_fetched_at: Time.now.utc,
expires_at: expires_at,
options: latest_options,
cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }
cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 },
voters_count: voters_count
)
rescue ActiveRecord::StaleObjectError
poll.reload

View file

@ -174,7 +174,7 @@ class PostStatusService < BaseService
def poll_attributes
return if @options[:poll].blank?
@options[:poll].merge(account: @account)
@options[:poll].merge(account: @account, voters_count: 0)
end
def scheduled_options

View file

@ -12,12 +12,24 @@ class VoteService < BaseService
@choices = choices
@votes = []
ApplicationRecord.transaction do
@choices.each do |choice|
@votes << @poll.votes.create!(account: @account, choice: choice)
already_voted = true
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
already_voted = @poll.votes.where(account: @account).exists?
ApplicationRecord.transaction do
@choices.each do |choice|
@votes << @poll.votes.create!(account: @account, choice: choice)
end
end
else
raise Mastodon::RaceConditionError
end
end
increment_voters_count! unless already_voted
ActivityTracker.increment('activity:interactions')
if @poll.account.local?
@ -53,4 +65,18 @@ class VoteService < BaseService
def build_json(vote)
Oj.dump(serialize_payload(vote, ActivityPub::VoteSerializer))
end
def increment_voters_count!
unless @poll.voters_count.nil?
@poll.voters_count = @poll.voters_count + 1
@poll.save
end
rescue ActiveRecord::StaleObjectError
@poll.reload
retry
end
def lock_options
{ redis: Redis.current, key: "vote:#{@poll.id}:#{@account.id}" }
end
end