]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
edit throttling
authorEvan Prodromou <evan@prodromou.name>
Wed, 10 Dec 2008 17:47:22 +0000 (12:47 -0500)
committerEvan Prodromou <evan@prodromou.name>
Wed, 10 Dec 2008 17:47:22 +0000 (12:47 -0500)
darcs-hash:20081210174722-84dde-4c79d7f73230d008195bd19738bc9a6017b940e9.gz

classes/Notice.php
classes/Profile.php
classes/User.php
config.php.sample
lib/common.php

index 6d42a4f9af517dd21bacef981ab258ccfcf6337d..b85dccd23789345b339e36d23f6248575d9139dd 100644 (file)
@@ -38,14 +38,14 @@ class Notice extends Memcached_DataObject
     public $id;                              // int(4)  primary_key not_null
     public $profile_id;                      // int(4)   not_null
     public $uri;                             // varchar(255)  unique_key
-    public $content;                         // varchar(140)  
-    public $rendered;                        // text()  
-    public $url;                             // varchar(255)  
+    public $content;                         // varchar(140)
+    public $rendered;                        // text()
+    public $url;                             // varchar(255)
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
-    public $reply_to;                        // int(4)  
-    public $is_local;                        // tinyint(1)  
-    public $source;                          // varchar(32)  
+    public $reply_to;                        // int(4)
+    public $is_local;                        // tinyint(1)
+    public $source;                          // varchar(32)
 
     /* Static get */
     function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Notice',$k,$v); }
@@ -93,6 +93,11 @@ class Notice extends Memcached_DataObject
 
        static function saveNew($profile_id, $content, $source=NULL, $is_local=1, $reply_to=NULL, $uri=NULL) {
 
+        if (!Notice::checkEditThrottle($profile_id)) {
+            common_log(LOG_WARNING, 'Excessive posting by profile #' . $profile_id . '; throttled.');
+                       return _('Too many notices too fast; take a breather and post again in a few minutes.');
+        }
+
                $notice = new Notice();
                $notice->profile_id = $profile_id;
 
@@ -147,6 +152,24 @@ class Notice extends Memcached_DataObject
                return $notice;
        }
 
+    static function checkEditThrottle($profile_id) {
+        $profile = Profile::staticGet($profile_id);
+        if (!$profile) {
+            return false;
+        }
+        # Get the Nth notice
+        $notice = $profile->getNotices(common_config('throttle', 'count') - 1, 1);
+        if ($notice && $notice->fetch()) {
+            # If the Nth notice was posted less than timespan seconds ago
+            if (time() - strtotime($notice->created) <= common_config('throttle', 'timespan')) {
+                # Then we throttle
+                return false;
+            }
+        }
+        # Either not N notices in the stream, OR the Nth was not posted within timespan seconds
+        return true;
+    }
+
        function blowCaches($blowLast=false) {
                $this->blowSubsCache($blowLast);
                $this->blowNoticeCache($blowLast);
@@ -197,9 +220,9 @@ class Notice extends Memcached_DataObject
                if ($this->is_local) {
                        $cache = common_memcache();
                        if ($cache) {
-                               $cache->delete(common_cache_key('user:notices:'.$this->profile_id));
+                               $cache->delete(common_cache_key('profile:notices:'.$this->profile_id));
                                if ($blowLast) {
-                                       $cache->delete(common_cache_key('user:notices:'.$this->profile_id.';last'));
+                                       $cache->delete(common_cache_key('profile:notices:'.$this->profile_id.';last'));
                                }
                        }
                }
index 794dc1de93c8857e2f23c92f30930342fb7890c2..b57d7e38ddfd8913010415321df22ae5da584d98 100644 (file)
@@ -24,7 +24,7 @@ if (!defined('LACONICA')) { exit(1); }
  */
 require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
 
-class Profile extends Memcached_DataObject 
+class Profile extends Memcached_DataObject
 {
     ###START_AUTOCODE
     /* the code below is auto generated do not remove the above tag */
@@ -33,7 +33,7 @@ class Profile extends Memcached_DataObject
     public $id;                              // int(4)  primary_key not_null
     public $nickname;                        // varchar(64)  multiple_key not_null
     public $fullname;                        // varchar(255)  multiple_key
-    public $profileurl;                      // varchar(255)  
+    public $profileurl;                      // varchar(255)
     public $homepage;                        // varchar(255)  multiple_key
     public $bio;                             // varchar(140)  multiple_key
     public $location;                        // varchar(255)  multiple_key
@@ -145,4 +145,15 @@ class Profile extends Memcached_DataObject
                }
                return NULL;
        }
+
+       function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) {
+               $qry =
+                 'SELECT * ' .
+                 'FROM notice ' .
+                 'WHERE profile_id = %d ';
+
+               return Notice::getStream(sprintf($qry, $this->id),
+                                                                'profile:notices:'.$this->id,
+                                                                $offset, $limit, $since_id, $before_id);
+       }
 }
index 696c85e7373b45c4f4178403a28d8150c9c5173e..920b306670ac166549903b3155977bc2f84f3824 100644 (file)
@@ -25,7 +25,7 @@ if (!defined('LACONICA')) { exit(1); }
 require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
 require_once 'Validate.php';
 
-class User extends Memcached_DataObject 
+class User extends Memcached_DataObject
 {
     ###START_AUTOCODE
     /* the code below is auto generated do not remove the above tag */
@@ -33,7 +33,7 @@ class User extends Memcached_DataObject
     public $__table = 'user';                            // table name
     public $id;                              // int(4)  primary_key not_null
     public $nickname;                        // varchar(64)  unique_key
-    public $password;                        // varchar(255)  
+    public $password;                        // varchar(255)
     public $email;                           // varchar(255)  unique_key
     public $incomingemail;                   // varchar(255)  unique_key
     public $emailnotifysub;                  // tinyint(1)   default_1
@@ -41,23 +41,23 @@ class User extends Memcached_DataObject
     public $emailnotifynudge;                // tinyint(1)   default_1
     public $emailnotifymsg;                  // tinyint(1)   default_1
     public $emailmicroid;                    // tinyint(1)   default_1
-    public $language;                        // varchar(50)  
-    public $timezone;                        // varchar(50)  
+    public $language;                        // varchar(50)
+    public $timezone;                        // varchar(50)
     public $emailpost;                       // tinyint(1)   default_1
     public $jabber;                          // varchar(255)  unique_key
-    public $jabbernotify;                    // tinyint(1)  
-    public $jabberreplies;                   // tinyint(1)  
+    public $jabbernotify;                    // tinyint(1)
+    public $jabberreplies;                   // tinyint(1)
     public $jabbermicroid;                   // tinyint(1)   default_1
-    public $updatefrompresence;              // tinyint(1)  
+    public $updatefrompresence;              // tinyint(1)
     public $sms;                             // varchar(64)  unique_key
-    public $carrier;                         // int(4)  
-    public $smsnotify;                       // tinyint(1)  
-    public $smsreplies;                      // tinyint(1)  
-    public $smsemail;                        // varchar(255)  
+    public $carrier;                         // int(4)
+    public $smsnotify;                       // tinyint(1)
+    public $smsreplies;                      // tinyint(1)
+    public $smsemail;                        // varchar(255)
     public $uri;                             // varchar(255)  unique_key
-    public $autosubscribe;                   // tinyint(1)  
+    public $autosubscribe;                   // tinyint(1)
     public $urlshorteningservice;            // varchar(50)   default_ur1.ca
-    public $inboxed;                         // tinyint(1)  
+    public $inboxed;                         // tinyint(1)
     public $created;                         // datetime()   not_null
     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 
@@ -198,11 +198,11 @@ class User extends Memcached_DataObject
                }
 
                $inboxes = common_config('inboxes', 'enabled');
-               
+
                if ($inboxes === true || $inboxes == 'transitional') {
                        $user->inboxed = 1;
                }
-               
+
                $user->created = common_sql_now();
                $user->uri = common_user_uri($user);
 
@@ -277,13 +277,13 @@ class User extends Memcached_DataObject
                $cache = common_memcache();
 
                # XXX: Kind of a hack.
-               
+
                if ($cache) {
                        # This is the stream of favorite notices, in rev chron
                        # order. This forces it into cache.
                        $faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
                        $cnt = 0;
-                       
+
                        while ($faves->fetch()) {
                                if ($faves->id < $notice->id) {
                                        # If we passed it, it's not a fave
@@ -303,27 +303,27 @@ class User extends Memcached_DataObject
                        # Otherwise, cache doesn't have all faves;
                        # fall through to the default
                }
-               
+
                $fave = Fave::pkeyGet(array('user_id' => $this->id,
                                                                        'notice_id' => $notice->id));
                return ((is_null($fave)) ? false : true);
        }
-       
+
        function mutuallySubscribed($other) {
                return $this->isSubscribed($other) &&
                  $other->isSubscribed($this);
        }
-       
+
        function mutuallySubscribedUsers() {
 
                # 3-way join; probably should get cached
-               
+
                $qry = 'SELECT user.* ' .
                  'FROM subscription sub1 JOIN user ON sub1.subscribed = user.id ' .
                  'JOIN subscription sub2 ON user.id = sub2.subscriber ' .
                  'WHERE sub1.subscriber = %d and sub2.subscribed = %d ' .
                  'ORDER BY user.nickname';
-               
+
                $user = new User();
                $user->query(sprintf($qry, $this->id, $this->id));
 
@@ -335,41 +335,39 @@ class User extends Memcached_DataObject
                  'SELECT notice.* ' .
                  'FROM notice JOIN reply ON notice.id = reply.notice_id ' .
                  'WHERE reply.profile_id = %d ';
-               
+
                return Notice::getStream(sprintf($qry, $this->id),
                                                                 'user:replies:'.$this->id,
                                                                 $offset, $limit, $since_id, $before_id);
        }
-       
+
        function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) {
-               $qry =
-                 'SELECT * ' .
-                 'FROM notice ' .
-                 'WHERE profile_id = %d ';
-               
-               return Notice::getStream(sprintf($qry, $this->id),
-                                                                'user:notices:'.$this->id,
-                                                                $offset, $limit, $since_id, $before_id);
+        $profile = $this->getProfile();
+        if (!$profile) {
+            return NULL;
+        } else {
+            return $profile->getNotices($offset, $limit, $since_id, $before_id);
+        }
        }
-       
+
        function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE) {
                $qry =
                  'SELECT notice.* ' .
                  'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
                  'WHERE fave.user_id = %d ';
-               
+
                return Notice::getStream(sprintf($qry, $this->id),
                                                                 'user:faves:'.$this->id,
                                                                 $offset, $limit);
        }
-       
+
        function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) {
                $enabled = common_config('inboxes', 'enabled');
 
                # Complicated code, depending on whether we support inboxes yet
                # XXX: make this go away when inboxes become mandatory
-               
-               if ($enabled === false || 
+
+               if ($enabled === false ||
                        ($enabled == 'transitional' && $this->inboxed == 0)) {
                        $qry =
                          'SELECT notice.* ' .
@@ -377,7 +375,7 @@ class User extends Memcached_DataObject
                          'WHERE subscription.subscriber = %d ';
                        $order = NULL;
                } else if ($enabled === true ||
-                                  ($enabled == 'transitional' && $this->inboxed == 1)) {                                  
+                                  ($enabled == 'transitional' && $this->inboxed == 1)) {
                        $qry =
                          'SELECT notice.* ' .
                          'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
@@ -385,13 +383,13 @@ class User extends Memcached_DataObject
                        # NOTE: we override ORDER
                        $order = 'ORDER BY notice_inbox.created DESC, notice_inbox.notice_id DESC ';
                }
-               
+
                return Notice::getStream(sprintf($qry, $this->id),
                                                                 'user:notices_with_friends:' . $this->id,
                                                                 $offset, $limit, $since_id, $before_id,
                                                                 $order);
        }
-       
+
        function blowFavesCache() {
                $cache = common_memcache();
                if ($cache) {
@@ -401,11 +399,11 @@ class User extends Memcached_DataObject
                        $cache->delete(common_cache_key('user:faves:'.$this->id).';last');
                }
        }
-       
+
        function getSelfTags() {
                return Profile_tag::getTags($this->id, $this->id);
        }
-       
+
        function setSelfTags($newtags) {
                return Profile_tag::setTags($this->id, $this->id, $newtags);
        }
index c2e7bf151a2dd2d7f66db868dcbaacfd1a2e1acd..1cfbffd8dda36421acbd2b11f69cc0952857809f 100644 (file)
@@ -61,7 +61,6 @@ $config['sphinx']['enabled'] = false;
 $config['sphinx']['server'] = 'localhost';
 $config['sphinx']['port'] = 3312;
 
-
 # Users to populate the 'Featured' tab
 #$config['nickname']['featured'][] = 'scobleizer';
 
@@ -93,7 +92,6 @@ $config['sphinx']['port'] = 3312;
 #For incoming email, if enabled. Defaults to site server name.
 #$config['mail']['domain'] = 'incoming.example.net';
 
-
 #exponential decay factor for tags, default 10 days
 #raise this if traffic is slow, lower it if it's fast
 #$config['tag']['dropoff'] = 86400.0 * 10;
@@ -124,3 +122,11 @@ $config['sphinx']['port'] = 3312;
 
 #Twitter integration source attribute. Note: default is Laconica
 #$config['integration']['source'] = 'Laconica';
+
+# Edit throttling. Off by default. If turned on, you can only post 20 notices
+# every 10 minutes. Admins may want to play with the settings to minimize inconvenience for
+# real users without getting uncontrollable floods from spammers or runaway bots.
+
+#$config['throttle']['enabled'] = true;
+#$config['throttle']['count'] = 100;
+#$config['throttle']['timespan'] = 3600;
\ No newline at end of file
index f7fcffc1cef456ec0fd03c41b52a1364b8002bff..8543b09c7bf23368d1f217443d713eead2721453 100644 (file)
@@ -41,7 +41,7 @@ define_syslog_variables();
 # append our extlib dir as the last-resort place to find libs
 
 set_include_path(get_include_path() . PATH_SEPARATOR . INSTALLDIR . '/extlib/');
-                                
+
 # global configuration object
 
 require_once('PEAR.php');
@@ -92,6 +92,10 @@ $config =
                          'blacklist' => array()),
                'theme' =>
                array('server' => NULL),
+               'throttle' =>
+        array('enabled' => false, // whether to throttle edits; false by default
+              'count' => 20, // number of allowed messages in timespan
+              'timespan' => 600), // timespan for throttling
                'xmpp' =>
                array('enabled' => false,
                          'server' => 'INVALID SERVER',
@@ -115,7 +119,7 @@ $config =
                          'group' => false),
                'integration' =>
                array('source' => 'Laconica'), # source attribute for Twitter
-               'memcached' => 
+               'memcached' =>
                array('enabled' => false,
                          'server' => 'localhost',
                          'port' => 11211),