myexperiment-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[myexperiment-hackers] [2016] branches/invitation_throttling: Throttling


From: noreply
Subject: [myexperiment-hackers] [2016] branches/invitation_throttling: Throttling.
Date: Fri, 28 Nov 2008 14:07:01 -0500 (EST)

Revision
2016
Author
alekses6
Date
2008-11-28 14:07:01 -0500 (Fri, 28 Nov 2008)

Log Message

Throttling. User invitations to myExperiment / user invitations with friendship request are now limited.

Refactored code in the Invitation model - it doesn't make checks over the invitation limit; this is done in the users_controller instead.

Modified Paths

Diff

Modified: branches/invitation_throttling/app/controllers/users_controller.rb (2015 => 2016)


--- branches/invitation_throttling/app/controllers/users_controller.rb	2008-11-28 17:40:01 UTC (rev 2015)
+++ branches/invitation_throttling/app/controllers/users_controller.rb	2008-11-28 19:07:01 UTC (rev 2016)
@@ -366,8 +366,25 @@
   
   # For sending invitation emails
   def invite
+    sending_allowed_with_reset_timestamp = ActivityLimit.check_limit(current_user, "user_invite", false)
+    
     respond_to do |format|
-      format.html # invite.rhtml
+      if sending_allowed_with_reset_timestamp[0]
+        format.html # invite.rhtml
+      else
+        # limit of invitation for this user is already exceeded
+        error_msg = "You can't send invitations - your limit is reached, "
+        if sending_allowed_with_reset_timestamp[1].nil?
+          error_msg += "it will not be reset. Please contact myExperiment administration for details."
+        elsif sending_allowed_with_reset_timestamp[1] <= 60
+          error_msg += "please try again within a couple of minutes"
+        else
+          error_msg += "it will be reset in " + formatted_timespan(sending_allowed_with_reset_timestamp[1])
+        end
+        
+        flash[:error] = error_msg 
+        format.html { redirect_to user_path(current_user) }
+      end
     end
   end
   
@@ -381,15 +398,21 @@
     else
       # captcha verified correctly, can proceed
       
-      addr_count, validated_addr_count, valid_addresses, db_user_addresses, err_addresses, overflow_addresses = Invitation.validate_address_list(params[:invitations][:addr_to])
+      addr_count, validated_addr_count, valid_addresses, db_user_addresses, err_addresses = Invitation.validate_address_list(params[:invitations][:addr_to], current_user)
       existing_invitation_emails = []
       valid_addresses_tokens = {}     # a hash for pairs of 'email' => 'token'
+      overflow_addresses = []
         
       # if validation found valid addresses, do the sending
+      # (limit on the number of invitation email is only checked where the actual email will be sent)
       if validated_addr_count > 0
         if params[:invitations][:as_friendship].nil?
           valid_addresses.each { |email_addr|
-            valid_addresses_tokens[email_addr] = "" 
+            if ActivityLimit.check_limit(current_user, "user_invite")[0]
+              valid_addresses_tokens[email_addr] = ""
+            else
+              overflow_addresses << email_addr
+            end
           }
           Invitation.send_invitation_emails("invite", base_host, User.find(params[:invitations_user_id]), valid_addresses_tokens, params[:invitations][:msg_text])
         elsif params[:invitations][:as_friendship] == "true"
@@ -399,10 +422,14 @@
             if PendingInvitation.find_by_email_and_request_type_and_request_for(email_addr, "friendship", params[:invitations_user_id])
               existing_invitation_emails << email_addr
             else 
-              token_code = Digest::SHA1.hexdigest( email_addr.reverse + SECRET_WORD )
-              valid_addresses_tokens[email_addr] = token_code
-              invitation = PendingInvitation.new(:email => email_addr, :request_type => "friendship", :requested_by => params[:invitations_user_id], :request_for => params[:invitations_user_id], :message => params[:invitations][:msg_text], :token => token_code)
-              invitation.save
+              if ActivityLimit.check_limit(current_user, "user_invite")[0]
+                token_code = Digest::SHA1.hexdigest( email_addr.reverse + SECRET_WORD )
+                valid_addresses_tokens[email_addr] = token_code
+                invitation = PendingInvitation.new(:email => email_addr, :request_type => "friendship", :requested_by => params[:invitations_user_id], :request_for => params[:invitations_user_id], :message => params[:invitations][:msg_text], :token => token_code)
+                invitation.save
+              else
+                overflow_addresses << email_addr
+              end
             end
           end
           
@@ -487,7 +514,17 @@
           end
           
           unless overflow_addresses.empty?
-            error_msg += "<br/><br/>You can only send invitations to #{INVITATION_EMAIL_LIMIT} unique, valid, non-blank email addresses.<br/>The following addresses were not processed because of maximum allowed amount was exceeded:<br/>" + overflow_addresses.join("<br/>")
+            error_msg += "<br/><br/>You have ran out of quota for sending invitations, "
+            reset_quota_after = ActivityLimit.check_limit(current_user, "user_invite", false)[1]
+            if reset_quota_after.nil?
+              error_msg += "it will not be reset. Please contact myExperiment administration for details."
+            elsif reset_quota_after <= 60
+              error_msg += "please try again within a couple of minutes."
+            else
+              error_msg += "it will be reset in " + formatted_timespan(reset_quota_after) + "."
+            end
+            
+            error_msg += "<br/>The following addresses were not processed because maximum allowed amount of invitations was exceeded:<br/>" + overflow_addresses.join("<br/>")
           end
           
           error_msg += "</span>"

Modified: branches/invitation_throttling/app/models/invitation.rb (2015 => 2016)


--- branches/invitation_throttling/app/models/invitation.rb	2008-11-28 17:40:01 UTC (rev 2015)
+++ branches/invitation_throttling/app/models/invitation.rb	2008-11-28 19:07:01 UTC (rev 2016)
@@ -12,17 +12,12 @@
   # 3) array of valid addresses
   # 4) hash of pairs ("existing_db_address" -> user_id)
   # 5) array of erroneous addresses
-  # 6) array of addresses that didn't fit into the EMAIL_LIMIT boundary
-  def self.validate_address_list (emails_csv_string)
+  def self.validate_address_list (emails_csv_string, current_user)
     
-    # check if need to set a limit on the number of emails to be processed
-    restrict_email_count = (INVITATION_EMAIL_LIMIT == -1 ? false : true)
-    
     # calling code relies on the 'err_addresses' variable being initialized to [] at the beginning
     err_addresses = []
     valid_addresses = []
     db_user_addresses = {}
-    overflow_addresses = []
     
     addr_cnt = 0
     validated_addr_cnt = 0
@@ -44,22 +39,13 @@
         if email_addr.downcase.match(/address@hidden,4}$/)
           # email_addr is validated if we are here;          
 
-          # check if we didn't exceed the INVITATION_EMAIL_LIMIT boundary yet 
-          if restrict_email_count && addr_cnt <= INVITATION_EMAIL_LIMIT
-            # if we didn't,
-            # check if it is also present in the DB as registered address of some user -
-            # if so, it needs to be treated differentrly
-            if( u = User.find(:first, :conditions => ["email = ? OR unconfirmed_email = ?", email_addr, email_addr]) )
-              db_user_addresses[email_addr] = u.id    
-            else
-              validated_addr_cnt += 1
-              valid_addresses << email_addr  
-            end
+          # check if it is also present in the DB as registered address of some user -
+          # if so, it needs to be treated differentrly
+          if( u = User.find(:first, :conditions => ["email = ? OR unconfirmed_email = ?", email_addr, email_addr]) )
+            db_user_addresses[email_addr] = u.id    
           else
-            # we did exceed the limit, but the goal is to
-            # only allow sending of not more than INVITATION_EMAIL_LIMIT emails / invitations;
-            # the ones that are after the INVITATION_EMAIL_LIMIT boundary will not be processed at all
-            overflow_addresses << email_addr 
+            validated_addr_cnt += 1
+            valid_addresses << email_addr  
           end
         else
           err_addresses << email_addr
@@ -69,7 +55,7 @@
     }
     
     
-    return [addr_cnt, validated_addr_cnt, valid_addresses, db_user_addresses, err_addresses, overflow_addresses]
+    return [addr_cnt, validated_addr_cnt, valid_addresses, db_user_addresses, err_addresses]
   end
   
   

Modified: branches/invitation_throttling/config/environment_private.rb.pre (2015 => 2016)


--- branches/invitation_throttling/config/environment_private.rb.pre	2008-11-28 17:40:01 UTC (rev 2015)
+++ branches/invitation_throttling/config/environment_private.rb.pre	2008-11-28 19:07:01 UTC (rev 2016)
@@ -81,4 +81,40 @@
 #
 # It is essential to put patterns into the ignore list in a single quotes - this will enable the
 # patterns to be treated as regular expressions, not just strings
-BOT_IGNORE_LIST = ['Googlebot', 'Slurp', 'msnbot', 'crawler', 'bot', 'heritrix', 'spider', 'Nutch']
\ No newline at end of file
+BOT_IGNORE_LIST = ['Googlebot', 'Slurp', 'msnbot', 'crawler', 'bot', 'heritrix', 'spider', 'Nutch']
+
+
+# =========== Settings for Activity Limits ===========
+
+# Each limited feature will require a set of 5 settings; meanings of each described below.
+# First part of every setting is the name of the feature being limited.
+# <feature_name>_LIMIT_START_VALUE - the initial maximum allowance for the feature (used when the new limit is created)  
+# <feature_name>_LIMIT_MAX_VALUE - absolute maximum allowance for the feature (this can't be exceeded after any promotions);
+#                                  NULL for always increasing allowance
+# <feature_name>_LIMIT_FREQUENCY -- in hours -- the time period over which the allowance is given; for example 5 messages (allowance) for 24 hours (frequency)
+#                                               NULL for non-periodic limits (i.e. limits which won't have their counters reset every <frequency> hours)
+# <feature_name>_LIMIT_PROMOTE_EVERY -- in days -- every <X> days the user will be promoted to the new level, 
+#                                                  where the allowance per frequency period will be adjusted by <feature_name>_LIMIT_PROMOTE_INCREMENT;
+#                                                  NULL to indicate that promotion should never happen
+# <feature_name>_LIMIT_PROMOTE_INCREMENT - should be positive; 
+#                                          0 to indicate that promotion shouldn't expand the allowance (why would this be useful?)
+#                                          NULL to perform a one-time promotion by setting the limit to whatever the value of <feature_name>_LIMIT_MAX_VALUE is;
+#                                          NULL when the <feature_name>_LIMIT_MAX_VALUE is also NULL makes the feature unlimited.
+
+INTERNAL_MESSAGE_LIMIT_START_VALUE = 10
+INTERNAL_MESSAGE_LIMIT_MAX_VALUE = 50
+INTERNAL_MESSAGE_LIMIT_FREQUENCY = 24 # hours
+INTERNAL_MESSAGE_LIMIT_PROMOTE_EVERY = 30 # days
+INTERNAL_MESSAGE_LIMIT_PROMOTE_INCREMENT = 10
+
+USER_INVITE_LIMIT_START_VALUE = 5
+USER_INVITE_LIMIT_MAX_VALUE = 30
+USER_INVITE_LIMIT_FREQUENCY = 24 # hours
+USER_INVITE_LIMIT_PROMOTE_EVERY = 30 # days
+USER_INVITE_LIMIT_PROMOTE_INCREMENT = 5
+
+GROUP_INVITE_LIMIT_START_VALUE = 5
+GROUP_INVITE_LIMIT_MAX_VALUE = 30
+GROUP_INVITE_LIMIT_FREQUENCY = 24 # hours
+GROUP_INVITE_LIMIT_PROMOTE_EVERY = 30 # days
+GROUP_INVITE_LIMIT_PROMOTE_INCREMENT = 5

reply via email to

[Prev in Thread] Current Thread [Next in Thread]