From 171c47e0a204186e372eb46dfe68a8e6e66e956a Mon Sep 17 00:00:00 2001 From: Andrew Garrett Date: Fri, 27 Jun 2008 06:24:42 +0000 Subject: [PATCH] Core changes for AbuseFilter extension. In particular: Xml.php * Add textarea method to Xml class. * Make submit button optional for Xml::buildForm * Right-align labels in buildForm. Article.php: * Make ArticleDelete hook display a real error EditPage.php: * Split off getBaseRevision() Title.php: * Allow errors to be ignored to be sent to getUserPermissionsErrors. * Allow AbortMove hook to display a real error. Block.php: * Add 'mAngryAutoblock' option, for blocks by software, which does retroactive autoblocks on the last 5 IPs used in the last 7 days. --- includes/Article.php | 9 +++++++-- includes/Block.php | 28 +++++++++++++++++++++------- includes/EditPage.php | 15 +++++++++++++-- includes/Title.php | 13 ++++++++++++- includes/Xml.php | 35 +++++++++++++++++++++++++++-------- 5 files changed, 80 insertions(+), 20 deletions(-) diff --git a/includes/Article.php b/includes/Article.php index bce720233a..2ce69059c1 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -2250,8 +2250,10 @@ class Article { wfDebug( __METHOD__."\n" ); $id = $this->getId(); + + $error = ''; - if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) { + if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason, &$error))) { if ( $this->doDeleteArticle( $reason, $suppress ) ) { $deleted = $this->mTitle->getPrefixedText(); @@ -2264,7 +2266,10 @@ class Article { $wgOut->returnToMain( false ); wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason, $id)); } else { - $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); + if ($error = '') + $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); + else + $wgOut->showFatalError( $error ); } } } diff --git a/includes/Block.php b/includes/Block.php index 2a1ad69a2f..b400912b12 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -17,7 +17,7 @@ class Block { /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry, $mRangeStart, $mRangeEnd, $mAnonOnly, $mEnableAutoblock, $mHideName, - $mBlockEmail, $mByName; + $mBlockEmail, $mByName, $mAngryAutoblock; /* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate, $mFromMaster; const EB_KEEP_EXPIRED = 1; @@ -46,6 +46,7 @@ class Block $this->mForUpdate = false; $this->mFromMaster = false; $this->mByName = false; + $this->mAngryAutoblock = false; $this->initialiseRange(); } @@ -430,17 +431,30 @@ class Block if ($this->mEnableAutoblock && $this->mUser) { wfDebug("Doing retroactive autoblocks for " . $this->mAddress . "\n"); + + $options = array( 'ORDER BY' => 'rc_timestamp DESC' ); + $conds = array( 'rc_user_text' => $this->mAddress ); + + if ($this->mAngryAutoblock) { + // Block any IP used in the last 7 days. Up to five IPs. + $conds[] = 'rc_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( time() - (7*86400) ) ); + $options['LIMIT'] = 5; + } else { + // Just the last IP used. + $options['LIMIT'] = 1; + } - $row = $dbr->selectRow( 'recentchanges', array( 'rc_ip' ), array( 'rc_user_text' => $this->mAddress ), - __METHOD__ , array( 'ORDER BY' => 'rc_timestamp DESC' ) ); + $res = $dbr->select( 'recentchanges', array( 'rc_ip' ), $conds, + __METHOD__ , $options); - if ( !$row || !$row->rc_ip ) { + if ( !$dbr->numRows( $res ) ) { #No results, don't autoblock anything wfDebug("No IP found to retroactively autoblock\n"); } else { - #Limit is 1, so no loop needed. - $retroblockip = $row->rc_ip; - return $this->doAutoblock( $retroblockip, true ); + while ( $row = $dbr->fetchObject( $res ) ) { + if ( $row->rc_ip ) + $this->doAutoblock( $row->rc_ip ); + } } } } diff --git a/includes/EditPage.php b/includes/EditPage.php index e861b4b6f3..c898b9a272 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -62,6 +62,7 @@ class EditPage { var $autoSumm = ''; var $hookError = ''; var $mPreviewTemplates; + var $mBaseRevision = false; # Form values var $save = false, $preview = false, $diff = false; @@ -1722,8 +1723,7 @@ END $db = wfGetDB( DB_MASTER ); // This is the revision the editor started from - $baseRevision = Revision::loadFromTimestamp( - $db, $this->mTitle, $this->edittime ); + $baseRevision = $this->getBaseRevision(); if( is_null( $baseRevision ) ) { wfProfileOut( $fname ); return false; @@ -2321,4 +2321,15 @@ END return false; } } + + function getBaseRevision() { + if ($this->mBaseRevision == false) { + $db = wfGetDB( DB_MASTER ); + $baseRevision = Revision::loadFromTimestamp( + $db, $editor->mTitle, $editor->edittime ); + return $this->mBaseRevision = $baseRevision; + } else { + return $this->mBaseRevision; + } + } } diff --git a/includes/Title.php b/includes/Title.php index 8cbbbd153d..1b0512bbea 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -1049,9 +1049,10 @@ class Title { * @param string $action action that permission needs to be checked for * @param User $user user to check * @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries. + * @param array $ignoreErrors Set this to a list of message keys whose corresponding errors may be ignored. * @return array Array of arrays of the arguments to wfMsg to explain permissions problems. */ - public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true ) { + public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) { if( !StubObject::isRealObject( $user ) ) { //Since StubObject is always used on globals, we can unstub $wgUser here and set $user = $wgUser global $wgUser; @@ -1116,6 +1117,16 @@ class Title { $errors[] = array( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name, $blockid, $blockExpiry, $intended, $blockTimestamp ); } + + // Remove the errors being ignored. + + foreach( $errors as $index => $error ) { + $error_key = is_array($error) ? $error[0] : $error; + + if (in_array( $error_key, $ignoreErrors )) { + unset($errors[$index]); + } + } return $errors; } diff --git a/includes/Xml.php b/includes/Xml.php index 9f9be3c7e6..4feff6d22a 100644 --- a/includes/Xml.php +++ b/includes/Xml.php @@ -472,6 +472,25 @@ class Xml { return $s; } + + /** + * Shortcut for creating textareas. + * + * @param $name The 'name' for the textarea + * @param $content Content for the textarea + * @param $cols The number of columns for the textarea + * @param $rows The number of rows for the textarea + * @param $attribs Any other attributes for the textarea + */ + public static function textarea( $name, $content, $cols = 40, $rows = 5, $attribs = array() ) { + return self::element( 'textarea', + array( 'name' => $name, + 'id' => $name, + 'cols' => $cols, + 'rows' => $rows + ) + $attribs, + $content ); + } /** * Returns an escaped string suitable for inclusion in a string literal @@ -606,29 +625,29 @@ class Xml { /** * Generate a form (without the opening form element). - * Output DOES include a submit button. + * Output optionally includes a submit button. * @param $fields Associative array, key is message corresponding to a description for the field (colon is in the message), value is appropriate input. * @param $submitLabel A message containing a label for the submit button. * @return string HTML form. */ - public static function buildForm( $fields, $submitLabel ) { + public static function buildForm( $fields, $submitLabel = null ) { $form = ''; $form .= ""; foreach( $fields as $labelmsg => $input ) { $id = "mw-$labelmsg"; + $form .= Xml::openElement( 'tr', array( 'id' => $id ) ); - - $form .= Xml::element( 'td', array('valign' => 'top'), wfMsg( $labelmsg ) ); - + $form .= Xml::tags( 'td', array('valign'=>'top','align' => 'right'), wfMsgExt( $labelmsg, array('parseinline') ) ); $form .= Xml::openElement( 'td' ) . $input . Xml::closeElement( 'td' ); - $form .= Xml::closeElement( 'tr' ); } $form .= "
"; - - $form .= Xml::submitButton( wfMsg($submitLabel) ); + + if ($submitLabel) { + $form .= Xml::submitButton( wfMsg($submitLabel) ); + } return $form; } -- 2.20.1