From: Roan Kattouw Date: Tue, 15 Jan 2008 17:31:07 +0000 (+0000) Subject: Large refactoring of rollback code: X-Git-Tag: 1.31.0-rc.0~49983 X-Git-Url: http://git.cyclocoop.org/%24image?a=commitdiff_plain;h=763d059ec020cfa31bf7a1efa9e4b8b2c654c36e;p=lhc%2Fweb%2Fwiklou.git Large refactoring of rollback code: * DB code is now in Article::commitRollback(), permissions checks in Article::doRollback() * doRollback() no longer returns named constants but an OutputPage::showPermissionsErrorPage() compatible array --- diff --git a/includes/Article.php b/includes/Article.php index 9ca021cca5..050d57ab7d 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -36,19 +36,6 @@ class Article { var $mUserText; //!< /**@}}*/ - /** - * Constants used by internal components to get rollback results - */ - const SUCCESS = 0; // Operation successful - const PERM_DENIED = 1; // Permission denied - const BLOCKED = 2; // User has been blocked - const READONLY = 3; // Wiki is in read-only mode - const BAD_TOKEN = 4; // Invalid token specified - const BAD_TITLE = 5; // $this is not a valid Article - const ALREADY_ROLLED = 6; // Someone else already rolled this back. $from and $summary will be set - const ONLY_AUTHOR = 7; // User is the only author of the page - const RATE_LIMITED = 8; - /** * Constructor and clear the article * @param $title Reference to a Title object. @@ -2273,57 +2260,73 @@ class Article { /** * Roll back the most recent consecutive set of edits to a page * from the same user; fails if there are no eligible edits to - * roll back to, e.g. user is the sole contributor + * roll back to, e.g. user is the sole contributor. This function + * performs permissions checks on $wgUser, then calls commitRollback() + * to do the dirty work * * @param string $fromP - Name of the user whose edits to rollback. * @param string $summary - Custom summary. Set to default summary if empty. * @param string $token - Rollback token. * @param bool $bot - If true, mark all reverted edits as bot. * - * @param array $resultDetails contains result-specific dict of additional values - * ALREADY_ROLLED : 'current' (rev) - * SUCCESS : 'summary' (str), 'current' (rev), 'target' (rev) + * @param array $resultDetails contains result-specific array of additional values + * 'alreadyrolled' : 'current' (rev) + * success : 'summary' (str), 'current' (rev), 'target' (rev) * - * @return self::SUCCESS on succes, self::* on failure + * @return array of errors, each error formatted as array(messagekey, param1, param2, ...). + * On success, the array is empty. This array can also be passed to OutputPage::showPermissionsErrorPage(). + * NOTE: If the user is blocked, 'blocked' is passed as a message, but it doesn't exist. Be sure to check + * it before calling showPermissionsErrorPage(). The same is true for 'actionthrottledtext', which + * is passed if the rate limit is passed. */ public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails ) { - global $wgUser, $wgUseRCPatrol; + global $wgUser; $resultDetails = null; - # Just in case it's being called from elsewhere - - if( $wgUser->isAllowed( 'rollback' ) && $this->mTitle->userCan( 'edit' ) ) { - if( $wgUser->isBlocked() ) { - return self::BLOCKED; - } - } else { - return self::PERM_DENIED; - } - - if ( wfReadOnly() ) { - return self::READONLY; - } - + # Check permissions + $errors = array_merge( $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser ), + $this->mTitle->getUserPermissionsErrors( 'rollback', $wgUser ) ); if( !$wgUser->matchEditToken( $token, array( $this->mTitle->getPrefixedText(), $fromP ) ) ) - return self::BAD_TOKEN; + $errors[] = array( 'sessionfailure' ); if ( $wgUser->pingLimiter('rollback') || $wgUser->pingLimiter() ) { - return self::RATE_LIMITED; + $errors[] = array( 'actionthrottledtext' ); } + if ( $wgUser->isBlocked() ) + $errors[] = array( 'blocked' ); + # If there were errors, bail out now + if(!empty($errors)) + return $errors; + + return $this->commitRollback($fromP, $summary, $bot, $resultDetails); + } + + /** + * Backend implementation of doRollback(), please refer there for parameter and return value documentation + * + * NOTE: This function does NOT check ANY permissions, it just commits the rollback to the DB. + * Therefore, you should only call this function directly if you really know what you're doing. If you don't, use doRollback() instead + */ + public function commitRollback($fromP, $summary, $bot, &$resultDetails) { + global $wgUseRCPatrol; $dbw = wfGetDB( DB_MASTER ); # Get the last editor $current = Revision::newFromTitle( $this->mTitle ); if( is_null( $current ) ) { # Something wrong... no page? - return self::BAD_TITLE; + return array(array('notanarticle')); } $from = str_replace( '_', ' ', $fromP ); if( $from != $current->getUserText() ) { $resultDetails = array( 'current' => $current ); - return self::ALREADY_ROLLED; + return array(array('alreadyrolled', + htmlspecialchars($this->mTitle->getPrefixedText()), + htmlspecialchars($fromP), + htmlspecialchars($current->getUserText()) + )); } # Get the last edit not by this guy @@ -2331,17 +2334,15 @@ class Article { $user_text = $dbw->addQuotes( $current->getUserText() ); $s = $dbw->selectRow( 'revision', array( 'rev_id', 'rev_timestamp' ), - array( - 'rev_page' => $current->getPage(), + array( 'rev_page' => $current->getPage(), "rev_user <> {$user} OR rev_user_text <> {$user_text}" ), __METHOD__, - array( - 'USE INDEX' => 'page_timestamp', + array( 'USE INDEX' => 'page_timestamp', 'ORDER BY' => 'rev_timestamp DESC' ) ); if( $s === false ) { - # Something wrong - return self::ONLY_AUTHOR; + # No one else ever edited this page + return array(array('cantrollback')); } $set = array(); @@ -2364,7 +2365,7 @@ class Article { ); } - # Get the edit summary + # Generate the edit summary if necessary $target = Revision::newFromId( $s->rev_id ); if( empty( $summary ) ) { @@ -2393,7 +2394,7 @@ class Article { 'current' => $current, 'target' => $target, ); - return self::SUCCESS; + return array(); } /** @@ -2401,19 +2402,8 @@ class Article { */ function rollback() { global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; - $details = null; - # Skip the permissions-checking in doRollback() itself, by checking permissions here. - - $perm_errors = array_merge( $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser ), - $this->mTitle->getUserPermissionsErrors( 'rollback', $wgUser ) ); - - if (count($perm_errors)) { - $wgOut->showPermissionsErrorPage( $perm_errors ); - return; - } - $result = $this->doRollback( $wgRequest->getVal( 'from' ), $wgRequest->getText( 'summary' ), @@ -2421,62 +2411,30 @@ class Article { $wgRequest->getBool( 'bot' ), $details ); - - switch( $result ) { - case self::BLOCKED: - $wgOut->blockedPage(); - break; - case self::PERM_DENIED: - $wgOut->permissionRequired( 'rollback' ); - break; - case self::READONLY: - $wgOut->readOnlyPage( $this->getContent() ); - break; - case self::BAD_TOKEN: - $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); - $wgOut->addWikiText( wfMsg( 'sessionfailure' ) ); - break; - case self::BAD_TITLE: - $wgOut->addHtml( wfMsg( 'notanarticle' ) ); - break; - case self::ALREADY_ROLLED: - $current = $details['current']; - $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); - $wgOut->addWikiText( - wfMsg( 'alreadyrolled', - htmlspecialchars( $this->mTitle->getPrefixedText() ), - htmlspecialchars( $wgRequest->getVal( 'from' ) ), - htmlspecialchars( $current->getUserText() ) - ) - ); - if( $current->getComment() != '' ) { - $wgOut->addHtml( wfMsg( 'editcomment', - $wgUser->getSkin()->formatComment( $current->getComment() ) ) ); - } - break; - case self::ONLY_AUTHOR: - $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); - $wgOut->addHtml( wfMsg( 'cantrollback' ) ); - break; - case self::RATE_LIMITED: - $wgOut->rateLimited(); - break; - case self::SUCCESS: - $current = $details['current']; - $target = $details['target']; - $wgOut->setPageTitle( wfMsg( 'actioncomplete' ) ); - $wgOut->setRobotPolicy( 'noindex,nofollow' ); - $old = $wgUser->getSkin()->userLink( $current->getUser(), $current->getUserText() ) - . $wgUser->getSkin()->userToolLinks( $current->getUser(), $current->getUserText() ); - $new = $wgUser->getSkin()->userLink( $target->getUser(), $target->getUserText() ) - . $wgUser->getSkin()->userToolLinks( $target->getUser(), $target->getUserText() ); - $wgOut->addHtml( wfMsgExt( 'rollback-success', array( 'parse', 'replaceafter' ), $old, $new ) ); - $wgOut->returnToMain( false, $this->mTitle ); - break; - default: - throw new MWException( __METHOD__ . ": Unknown return value `{$result}`" ); + + if(in_array(array('blocked'), $result)) { + $wgOut->blockedPage(); + return; + } + if(in_array(array('actionthrottledtext'), $result)) { + $wgOut->rateLimited(); + return; + } + if(!empty($result)) { + $wgOut->showPermissionsErrorPage( $result ); + return; } + $current = $details['current']; + $target = $details['target']; + $wgOut->setPageTitle( wfMsg( 'actioncomplete' ) ); + $wgOut->setRobotPolicy( 'noindex,nofollow' ); + $old = $wgUser->getSkin()->userLink( $current->getUser(), $current->getUserText() ) + . $wgUser->getSkin()->userToolLinks( $current->getUser(), $current->getUserText() ); + $new = $wgUser->getSkin()->userLink( $target->getUser(), $target->getUserText() ) + . $wgUser->getSkin()->userToolLinks( $target->getUser(), $target->getUserText() ); + $wgOut->addHtml( wfMsgExt( 'rollback-success', array( 'parse', 'replaceafter' ), $old, $new ) ); + $wgOut->returnToMain( false, $this->mTitle ); }