diff options
author | ThibG <thib@sitedethib.com> | 2019-09-29 22:58:01 +0200 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2019-09-29 22:58:01 +0200 |
commit | 3babf8464b0903b854ec16d355909444ef3ca0bc (patch) | |
tree | ec5e2bd9217ac2ef69925827ed9c3ca614c31826 /app/lib | |
parent | cfe2d1cc4a3c531741fd769241593ebbe03b6711 (diff) |
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”
Diffstat (limited to 'app/lib')
-rw-r--r-- | app/lib/activitypub/activity/create.rb | 40 | ||||
-rw-r--r-- | app/lib/activitypub/adapter.rb | 1 |
2 files changed, 36 insertions, 5 deletions
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index e69193b71..76bf9b2e5 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -232,25 +232,40 @@ class ActivityPub::Activity::Create < ActivityPub::Activity items = @object['oneOf'] end + voters_count = @object['votersCount'] + @account.polls.new( multiple: multiple, expires_at: expires_at, options: items.map { |item| item['name'].presence || item['content'] }.compact, - cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 } + cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }, + voters_count: voters_count ) end def poll_vote? return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name']) - unless replied_to_status.preloadable_poll.expired? - replied_to_status.preloadable_poll.votes.create!(account: @account, choice: replied_to_status.preloadable_poll.options.index(@object['name']), uri: @object['id']) - ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals? - end + poll_vote! unless replied_to_status.preloadable_poll.expired? true end + def poll_vote! + poll = replied_to_status.preloadable_poll + already_voted = true + RedisLock.acquire(poll_lock_options) do |lock| + if lock.acquired? + already_voted = poll.votes.where(account: @account).exists? + poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: @object['id']) + else + raise Mastodon::RaceConditionError + end + end + increment_voters_count! unless already_voted + ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals? + end + def resolve_thread(status) return unless status.reply? && status.thread.nil? && Request.valid_url?(in_reply_to_uri) ThreadResolveWorker.perform_async(status.id, in_reply_to_uri) @@ -416,7 +431,22 @@ class ActivityPub::Activity::Create < ActivityPub::Activity ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url]) end + def increment_voters_count! + poll = replied_to_status.preloadable_poll + 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: "create:#{@object['id']}" } end + + def poll_lock_options + { redis: Redis.current, key: "vote:#{replied_to_status.poll_id}:#{@account.id}" } + end end diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb index cb2ac72d4..2a8f72333 100644 --- a/app/lib/activitypub/adapter.rb +++ b/app/lib/activitypub/adapter.rb @@ -21,6 +21,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' }, blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' }, discoverable: { 'toot' => 'http://joinmastodon.org/ns#', 'discoverable' => 'toot:discoverable' }, + voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' }, }.freeze def self.default_key_transform |