about summary refs log tree commit diff
path: root/app/services/vote_service.rb
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2019-09-30 12:23:57 +0200
committerThibaut Girka <thib@sitedethib.com>2019-09-30 12:23:57 +0200
commit16ff7c5627c12a0c9658e9d2fac7c48002e1b788 (patch)
tree465a73fb9f42bc2b01127b2d477b0715fb6185b4 /app/services/vote_service.rb
parentfebcdad2e2c98aee62b55ee21bdf0debf7c6fd6b (diff)
parent3babf8464b0903b854ec16d355909444ef3ca0bc (diff)
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts:
- Gemfile
- Gemfile.lock
- app/controllers/about_controller.rb
- app/controllers/auth/sessions_controller.rb
Diffstat (limited to 'app/services/vote_service.rb')
-rw-r--r--app/services/vote_service.rb32
1 files changed, 29 insertions, 3 deletions
diff --git a/app/services/vote_service.rb b/app/services/vote_service.rb
index 0eeb8fd56..cb7dce6e8 100644
--- a/app/services/vote_service.rb
+++ b/app/services/vote_service.rb
@@ -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