about summary refs log tree commit diff
path: root/app/models
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2020-03-08 15:17:39 +0100
committerGitHub <noreply@github.com>2020-03-08 15:17:39 +0100
commit339ce1c4e90605b736745b1f04493a247b2627ec (patch)
treebf6f6c697648416c0578fbc0e11132403a85b27c /app/models
parent503eab1c1f101e92f163ed4f8457cac9a6193ffc (diff)
Add specific rate limits for posting and following (#13172)
Diffstat (limited to 'app/models')
-rw-r--r--app/models/concerns/account_interactions.rb16
-rw-r--r--app/models/concerns/rate_limitable.rb36
-rw-r--r--app/models/follow.rb3
-rw-r--r--app/models/follow_request.rb3
-rw-r--r--app/models/status.rb3
5 files changed, 59 insertions, 2 deletions
diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb
index 14bcf7bb1..32fcb5397 100644
--- a/app/models/concerns/account_interactions.rb
+++ b/app/models/concerns/account_interactions.rb
@@ -87,10 +87,10 @@ module AccountInteractions
     has_many :announcement_mutes, dependent: :destroy
   end
 
-  def follow!(other_account, reblogs: nil, uri: nil)
+  def follow!(other_account, reblogs: nil, uri: nil, rate_limit: false)
     reblogs = true if reblogs.nil?
 
-    rel = active_relationships.create_with(show_reblogs: reblogs, uri: uri)
+    rel = active_relationships.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit)
                               .find_or_create_by!(target_account: other_account)
 
     rel.update!(show_reblogs: reblogs)
@@ -99,6 +99,18 @@ module AccountInteractions
     rel
   end
 
+  def request_follow!(other_account, reblogs: nil, uri: nil, rate_limit: false)
+    reblogs = true if reblogs.nil?
+
+    rel = follow_requests.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit)
+                         .find_or_create_by!(target_account: other_account)
+
+    rel.update!(show_reblogs: reblogs)
+    remove_potential_friendship(other_account)
+
+    rel
+  end
+
   def block!(other_account, uri: nil)
     remove_potential_friendship(other_account)
     block_relationships.create_with(uri: uri)
diff --git a/app/models/concerns/rate_limitable.rb b/app/models/concerns/rate_limitable.rb
new file mode 100644
index 000000000..ad1b5e44e
--- /dev/null
+++ b/app/models/concerns/rate_limitable.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module RateLimitable
+  extend ActiveSupport::Concern
+
+  def rate_limit=(value)
+    @rate_limit = value
+  end
+
+  def rate_limit?
+    @rate_limit
+  end
+
+  def rate_limiter(by, options = {})
+    return @rate_limiter if defined?(@rate_limiter)
+
+    @rate_limiter = RateLimiter.new(by, options)
+  end
+
+  class_methods do
+    def rate_limit(options = {})
+      after_create do
+        by = public_send(options[:by])
+
+        if rate_limit? && by&.local?
+          rate_limiter(by, options).record!
+          @rate_limit_recorded = true
+        end
+      end
+
+      after_rollback do
+        rate_limiter(public_send(options[:by]), options).rollback! if @rate_limit_recorded
+      end
+    end
+  end
+end
diff --git a/app/models/follow.rb b/app/models/follow.rb
index 87fa11425..f3e48a2ed 100644
--- a/app/models/follow.rb
+++ b/app/models/follow.rb
@@ -15,6 +15,9 @@
 class Follow < ApplicationRecord
   include Paginable
   include RelationshipCacheable
+  include RateLimitable
+
+  rate_limit by: :account, family: :follows
 
   belongs_to :account
   belongs_to :target_account, class_name: 'Account'
diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb
index 96ac7eaa5..3325e264c 100644
--- a/app/models/follow_request.rb
+++ b/app/models/follow_request.rb
@@ -15,6 +15,9 @@
 class FollowRequest < ApplicationRecord
   include Paginable
   include RelationshipCacheable
+  include RateLimitable
+
+  rate_limit by: :account, family: :follows
 
   belongs_to :account
   belongs_to :target_account, class_name: 'Account'
diff --git a/app/models/status.rb b/app/models/status.rb
index 1e630196b..1610da245 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -32,6 +32,9 @@ class Status < ApplicationRecord
   include Paginable
   include Cacheable
   include StatusThreadingConcern
+  include RateLimitable
+
+  rate_limit by: :account, family: :statuses
 
   self.discard_column = :deleted_at