* Implement an extensible Block::prevents( <action> ) function to replace the plethor...
authorHappy-melon <happy-melon@users.mediawiki.org>
Sat, 19 Mar 2011 23:47:08 +0000 (23:47 +0000)
committerHappy-melon <happy-melon@users.mediawiki.org>
Sat, 19 Mar 2011 23:47:08 +0000 (23:47 +0000)
* Implement accessors for isHardblock() and getRangeStart()/getRangeEnd() in the same fashion.
* Make the corresponding variables private, removing external accessors.  This required updating AbuseFilter with non-B/C code, so I also implemented the rest of the changes I've made to the blocking backend in that extension.
* Move the "get an IP range which encompasses the given IP/range" logic to Block.php; will be needed later... :D

includes/Block.php
includes/User.php
includes/specials/SpecialBlock.php
includes/specials/SpecialBlockList.php

index 06a0f44..5ca581b 100644 (file)
  */
 class Block {
        /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry,
-                               $mRangeStart, $mRangeEnd, $mAnonOnly, $mEnableAutoblock, $mHideName,
-                               $mBlockEmail, $mByName, $mAngryAutoblock, $mAllowUsertalk;
-       private $mFromMaster;
-
+                               $mEnableAutoblock, $mHideName,
+                               $mByName, $mAngryAutoblock;
+       private
+               $mFromMaster,
+               $mRangeStart,
+               $mRangeEnd,
+               $mAnonOnly,
+               $mBlockEmail,
+               $mAllowUsertalk,
+               $mCreateAccount;
+
+       /// TYPE constants
        const TYPE_USER = 1;
        const TYPE_IP = 2;
        const TYPE_RANGE = 3;
@@ -226,6 +234,54 @@ class Block {
                return false;
        }
 
+       /**
+        * Get a set of SQL conditions which will select rangeblocks encompasing a given range
+        * @param $start String Hexadecimal IP representation
+        * @param $end String Hexadecimal IP represenation, or null to use $start = $end
+        * @return String
+        */
+       public static function getRangeCond( $start, $end = null ){
+               if( $end === null ){
+                       $end = $start;
+               }
+               # Per bug 14634, we want to include relevant active rangeblocks; for
+               # rangeblocks, we want to include larger ranges which enclose the given
+               # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
+               # so we can improve performance by filtering on a LIKE clause
+               $chunk = self::getIpFragment( $start );
+               $dbr = wfGetDB( DB_SLAVE );
+               $like = $dbr->buildLike( $chunk, $dbr->anyString() );
+
+               # Fairly hard to make a malicious SQL statement out of hex characters,
+               # but stranger things have happened...
+               $safeStart = $dbr->addQuotes( $start );
+               $safeEnd = $dbr->addQuotes( $end );
+
+               return $dbr->makeList(
+                       array(
+                               "ipb_range_start $like",
+                               "ipb_range_start <= $safeStart",
+                               "ipb_range_end >= $safeEnd",
+                       ),
+                       LIST_AND
+               );
+       }
+
+       /**
+        * Get the component of an IP address which is certain to be the same between an IP
+        * address and a rangeblock containing that IP address.
+        * @param  $hex String Hexadecimal IP representation
+        * @return String
+        */
+       protected static function getIpFragment( $hex ){
+               global $wgBlockCIDRLimit;
+               if( substr( $hex, 0, 3 ) == 'v6-' ){
+                       return 'v6-' . substr( substr( $hex, 3 ), 0,  floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
+               } else {
+                       return substr( $hex, 0,  floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
+               }
+       }
+
        /**
         * Fill in member variables from a result wrapper
         *
@@ -706,6 +762,38 @@ class Block {
                }
        }
 
+       /**
+        * Get the IP address at the start of the range in Hex form
+        * @return String IP in Hex form
+        */
+       public function getRangeStart(){
+               switch( $this->type ){
+                       case self::TYPE_USER:
+                               return null;
+                       case self::TYPE_IP:
+                               return IP::toHex( $this->target );
+                       case self::TYPE_RANGE:
+                               return $this->mRangeStart;
+                       default: throw new MWException( "Block with invalid type" );
+               }
+       }
+
+       /**
+        * Get the IP address at the start of the range in Hex form
+        * @return String IP in Hex form
+        */
+       public function getRangeEnd(){
+               switch( $this->type ){
+                       case self::TYPE_USER:
+                               return null;
+                       case self::TYPE_IP:
+                               return IP::toHex( $this->target );
+                       case self::TYPE_RANGE:
+                               return $this->mRangeEnd;
+                       default: throw new MWException( "Block with invalid type" );
+               }
+       }
+
        /**
         * Get the user id of the blocking sysop
         *
@@ -739,6 +827,49 @@ class Block {
                return wfSetVar( $this->mFromMaster, $x );
        }
 
+       /**
+        * Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range
+        * @param $x Bool
+        * @return  Bool
+        */
+       public function isHardblock( $x = null ){
+               $y = $this->mAnonOnly;
+               if( $x !== null){
+                       $this->mAnonOnly = !$x;
+               }
+               return !$y;
+       }
+
+       /**
+        * Get/set whether the Block prevents a given action
+        * @param $action String
+        * @param $x Bool
+        * @return Bool
+        */
+       public function prevents( $action, $x = null ){
+               switch( $action ){
+                       case 'edit':
+                               # TODO Not actually quite this simple (bug 13611 etc)
+                               return true;
+
+                       case 'createaccount':
+                               return wfSetVar( $this->mCreateAccount, $x );
+
+                       case 'sendemail':
+                               return wfSetVar( $this->mBlockEmail, $x );
+
+                       case 'editusertalk':
+                               $y = $this->mAllowUsertalk;
+                               if( $x !== null){
+                                       $this->mAllowUsertalk = !$x;
+                               }
+                               return !$y;
+
+                       default:
+                               return null;
+               }
+       }
+
        /**
         * Get the block name, but with autoblocked IPs hidden as per standard privacy policy
         * @return String, text is escaped
index 218355d..5e21c17 100644 (file)
@@ -1157,7 +1157,7 @@ class User {
                                $this->mBlockedby = $this->mBlock->mByName;
                        $this->mBlockreason = $this->mBlock->mReason;
                        $this->mHideName = $this->mBlock->mHideName;
-                       $this->mAllowUsertalk = $this->mBlock->mAllowUsertalk;
+                       $this->mAllowUsertalk = !$this->mBlock->prevents( 'editusertalk' );
                        if ( $this->isLoggedIn() && $wgUser->getID() == $this->getID() ) {
                                $this->spreadBlock();
                        }
@@ -2801,7 +2801,7 @@ class User {
         */
        function isBlockedFromCreateAccount() {
                $this->getBlockedStatus();
-               return $this->mBlock && $this->mBlock->mCreateAccount;
+               return $this->mBlock && $this->mBlock->prevents( 'createaccount' );
        }
 
        /**
@@ -2810,7 +2810,7 @@ class User {
         */
        function isBlockedFromEmailuser() {
                $this->getBlockedStatus();
-               return $this->mBlock && $this->mBlock->mBlockEmail;
+               return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
        }
 
        /**
index 9f47b44..189f641 100644 (file)
@@ -208,17 +208,17 @@ class SpecialBlock extends SpecialPage {
                          || $block->mAddress == $this->target ) # or if it is, the range is what we're about to block
                        )
                {
-                       $fields['HardBlock']['default'] = !$block->mAnonOnly;
-                       $fields['CreateAccount']['default'] = $block->mCreateAccount;
+                       $fields['HardBlock']['default'] = $block->isHardblock();
+                       $fields['CreateAccount']['default'] = $block->prevents( 'createaccount' );
                        $fields['AutoBlock']['default'] = $block->mEnableAutoblock;
                        if( isset( $fields['DisableEmail'] ) ){
-                               $fields['DisableEmail']['default'] = $block->mBlockEmail;
+                               $fields['DisableEmail']['default'] = $block->prevents( 'sendemail' );
                        }
                        if( isset( $fields['HideUser'] ) ){
                                $fields['HideUser']['default'] = $block->mHideName;
                        }
                        if( isset( $fields['DisableUTEdit'] ) ){
-                               $fields['DisableUTEdit']['default'] = !$block->mAllowUsertalk;
+                               $fields['DisableUTEdit']['default'] = $block->prevents( 'editusertalk' );
                        }
                        $fields['Reason']['default'] = $block->mReason;
                        $fields['AlreadyBlocked']['default'] = true;
@@ -502,10 +502,6 @@ class SpecialBlock extends SpecialPage {
                        return array( 'ipb_expiry_invalid' );
                }
 
-               if( !$wgBlockAllowsUTEdit ){
-                       $data['DisableUTEdit'] = true;
-               }
-
                # If the user has done the form 'properly', they won't even have been given the
                # option to suppress-block unless they have the 'hideuser' permission
                if( !isset( $data['HideUser'] ) ){
@@ -548,10 +544,11 @@ class SpecialBlock extends SpecialPage {
                        !$data['HardBlock'],                        # Block anon only
                        $data['CreateAccount'],
                        $data['AutoBlock'],
-                       $data['HideUser'],
-                       $data['DisableEmail'],
-                       !$data['DisableUTEdit']                     # *Allow* UTEdit
+                       $data['HideUser']
                );
+               
+               $block->prevents( 'editusertalk', ( !$wgBlockAllowsUTEdit || $data['DisableUTEdit'] ) );
+               $block->prevents( 'sendemail', $data['DisableEmail'] );
 
                if( !wfRunHooks( 'BlockIp', array( &$block, &$wgUser ) ) ) {
                        return array( 'hookaborted' );
@@ -569,7 +566,7 @@ class SpecialBlock extends SpecialPage {
 
                                # This returns direct blocks before autoblocks/rangeblocks, since we should
                                # be sure the user is blocked by now it should work for our purposes
-                               $currentBlock = Block::newFromDB( $target, $userId );
+                               $currentBlock = Block::newFromTargetAndType( $target, $type );
 
                                if( $block->equals( $currentBlock ) ) {
                                        return array( 'ipb_already_blocked' );
@@ -613,7 +610,7 @@ class SpecialBlock extends SpecialPage {
                }
 
                # Block constructor sanitizes certain block options on insert
-               $data['BlockEmail'] = $block->mBlockEmail;
+               $data['BlockEmail'] = $block->prevents( 'sendemail' );
                $data['AutoBlock'] = $block->mEnableAutoblock;
 
                # Prepare log parameters
index 281d7e1..8b85663 100644 (file)
@@ -90,26 +90,6 @@ class SpecialBlockList extends SpecialPage {
                $this->showList();
        }
 
-       /**
-        * Get the component of an IP address which is certain to be the same between an IP
-        * address and a rangeblock containing that IP address.
-        * @todo: should be in IP.php??
-        * @param  $ip String
-        * @return String
-        */
-       protected static function getIpFragment( $ip ){
-               global $wgBlockCIDRLimit;
-               if( IP::isIPv4( $ip ) ){
-                       $hexAddress = IP::toHex( $ip );
-                       return substr( $hexAddress, 0,  wfBaseconvert( $wgBlockCIDRLimit['IPv4'], 10, 16 ) );
-               } elseif( IP::isIPv6( $ip ) ) {
-                       $hexAddress = substr( IP::toHex( $ip ), 2 );
-                       return 'v6-' . substr( $hexAddress, 0,  wfBaseconvert( $wgBlockCIDRLimit['IPv6'], 10, 16 ) );
-               } else {
-                       return null;
-               }
-       }
-
        function showList() {
                global $wgOut, $wgUser;
 
@@ -133,25 +113,16 @@ class SpecialBlockList extends SpecialPage {
                                        break;
 
                                case Block::TYPE_IP:
-                               case BLock::TYPE_RANGE:
+                               case Block::TYPE_RANGE:
                                        list( $start, $end ) = IP::parseRange( $target );
-                                       # Per bug 14634, we want to include relevant active rangeblocks; for
-                                       # rangeblocks, we want to include larger ranges which enclose the given
-                                       # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
-                                       # so we can improve performance by filtering on a LIKE clause
-                                       $chunk = self::getIpFragment( $start );
                                        $dbr = wfGetDB( DB_SLAVE );
-                                       $like = $dbr->buildLike( $chunk, $dbr->anyString() );
-
-                                       # Fairly hard to make a malicious SQL statement out of hex characters,
-                                       # but stranger things have happened...
-                                       $safeStart = $dbr->addQuotes( IP::toHex( $start ) );
-                                       $safeEnd = $dbr->addQuotes( IP::toHex( $end ) );
-                                       $safeTarget = $dbr->addQuotes( IP::toHex( $target ) );
-
-                                       # TODO: abstract this away
-                                       $conds[] = "(ipb_address = $safeTarget) OR
-                                               (ipb_range_start $like AND ipb_range_start <= $safeStart AND ipb_range_end >= $safeEnd)";
+                                       $conds[] = $dbr->makeList(
+                                               array(
+                                                       'ipb_address' => $target,
+                                                       Block::getRangeCond( $start, $end )
+                                               ),
+                                               LIST_OR
+                                       );
                                        $conds['ipb_auto'] = 0;
                                        break;