X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FArticle.php;h=efc4f6519261f15c774ba1f2b6482d93a7270c0a;hb=b76908589ab7134d3c95c33575ec721dcad89fd0;hp=286e97fdd540f47eecf2c075f0871c397d2ac2d6;hpb=8027310503e4a0d43f611f128177937d3a18fc2a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Article.php b/includes/Article.php index 286e97fdd5..efc4f65192 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -36,6 +36,18 @@ 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 + /** * Constructor and clear the article * @param $title Reference to a Title object. @@ -641,8 +653,6 @@ class Article { } elseif( isset( $wgNamespaceRobotPolicies[$ns] ) ) { # Honour customised robot policies for this namespace $policy = $wgNamespaceRobotPolicies[$ns]; - } elseif ( $this->mTitle->getRestrictions( 'robots' ) ) { - $policy = implode( ',', $this->mTitle->getRestrictions( 'robots' ) ); } else { # Default to encourage indexing and following links $policy = 'index,follow'; @@ -686,10 +696,12 @@ class Article { } # Should the parser cache be used? - $pcache = $wgEnableParserCache && - intval( $wgUser->getOption( 'stubthreshold' ) ) == 0 && - $this->exists() && - empty( $oldid ); + $pcache = $wgEnableParserCache + && intval( $wgUser->getOption( 'stubthreshold' ) ) == 0 + && $this->exists() + && empty( $oldid ) + && !$this->mTitle->isCssOrJsPage() + && !$this->mTitle->isCssJsSubpage(); wfDebug( 'Article::view using parser cache: ' . ($pcache ? 'yes' : 'no' ) . "\n" ); if ( $wgUser->getOption( 'stubthreshold' ) ) { wfIncrStats( 'pcache_miss_stub' ); @@ -779,15 +791,23 @@ class Article { } if( !$outputDone ) { $wgOut->setRevisionId( $this->getRevIdFetched() ); - # wrap user css and user js in pre and don't parse - # XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found - if ( - $ns == NS_USER && - preg_match('!/[\w]+\.(css|js)$!', $this->mTitle->getDBkey(), $matches) - ) { - $wgOut->addWikiText( wfMsg('clearyourcache')); - $wgOut->addHTML( "
".htmlspecialchars($this->mContent)."\n
" ); - } else if ( $rt = Title::newFromRedirect( $text ) ) { + + // Pages containing custom CSS or JavaScript get special treatment + if( $this->mTitle->isCssOrJsPage() || $this->mTitle->isCssJsSubpage() ) { + $wgOut->addHtml( wfMsgExt( 'clearyourcache', 'parse' ) ); + + // Give hooks a chance to customise the output + if( wfRunHooks( 'ShowRawCssJs', array( $this->mContent, $this->mTitle, $wgOut ) ) ) { + // Wrap the whole lot in a
 and don't parse
+					preg_match( '!\.(css|js)$!u', $this->mTitle->getText(), $m );
+					$wgOut->addHtml( "
\n" );
+					$wgOut->addHtml( htmlspecialchars( $this->mContent ) );
+					$wgOut->addHtml( "\n
\n" ); + } + + } + + elseif ( $rt = Title::newFromRedirect( $text ) ) { # Display redirect $imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr'; $imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png'; @@ -880,8 +900,8 @@ class Article { $rmvtxt = ""; if ($wgUser->isAllowed( 'trackback' )) { $delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid=" - . $o->tb_id . "&token=" . $wgUser->editToken()); - $rmvtxt = wfMsg('trackbackremove', $delurl); + . $o->tb_id . "&token=" . urlencode( $wgUser->editToken() ) ); + $rmvtxt = wfMsg( 'trackbackremove', htmlspecialchars( $delurl ) ); } $tbtext .= wfMsg(strlen($o->tb_ex) ? 'trackbackexcerpt' : 'trackback', $o->tb_title, @@ -1677,7 +1697,6 @@ class Article { $current = array(); foreach( $wgRestrictionTypes as $action ) $current[$action] = implode( '', $this->mTitle->getRestrictions( $action ) ); - $current['robots'] = implode( '', $this->mTitle->getRestrictions( 'robots' ) ); $current = Article::flattenRestrictions( $current ); $updated = Article::flattenRestrictions( $limit ); @@ -1713,9 +1732,7 @@ class Article { foreach( $limit as $action => $restrictions ) { # Check if the group level required to edit also can protect pages # Otherwise, people who cannot normally protect can "protect" pages via transclusion - if ( in_array( $restrictions, $wgRestrictionTypes ) ) { - $cascade = ( $cascade && isset($wgGroupPermissions[$restrictions]['protect']) && $wgGroupPermissions[$restrictions]['protect'] ); - } + $cascade = ( $cascade && isset($wgGroupPermissions[$restrictions]['protect']) && $wgGroupPermissions[$restrictions]['protect'] ); } $cascade_description = ''; @@ -2151,60 +2168,52 @@ class Article { } /** - * Revert a modification - */ - function rollback() { - global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; - + * 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 + * + * @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) + * + * @return self::SUCCESS on succes, self::* on failure + */ + public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails ) { + global $wgUser, $wgUseRCPatrol; + $resultDetails = null; + if( $wgUser->isAllowed( 'rollback' ) ) { if( $wgUser->isBlocked() ) { - $wgOut->blockedPage(); - return; + return self::BLOCKED; } } else { - $wgOut->permissionRequired( 'rollback' ); - return; + return self::PERM_DENIED; } - + if ( wfReadOnly() ) { - $wgOut->readOnlyPage( $this->getContent() ); - return; + return self::READONLY; } - if( !$wgUser->matchEditToken( $wgRequest->getVal( 'token' ), - array( $this->mTitle->getPrefixedText(), - $wgRequest->getVal( 'from' ) ) ) ) { - $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); - $wgOut->addWikiText( wfMsg( 'sessionfailure' ) ); - return; - } - $dbw = wfGetDB( DB_MASTER ); + if( !$wgUser->matchEditToken( $token, array( $this->mTitle->getPrefixedText(), $fromP ) ) ) + return self::BAD_TOKEN; - # Enhanced rollback, marks edits rc_bot=1 - $bot = $wgRequest->getBool( 'bot' ); - - # Replace all this user's current edits with the next one down + $dbw = wfGetDB( DB_MASTER ); # Get the last editor $current = Revision::newFromTitle( $this->mTitle ); if( is_null( $current ) ) { # Something wrong... no page? - $wgOut->addHTML( wfMsg( 'notanarticle' ) ); - return; + return self::BAD_TITLE; } - $from = str_replace( '_', ' ', $wgRequest->getVal( 'from' ) ); + $from = str_replace( '_', ' ', $fromP ); if( $from != $current->getUserText() ) { - $wgOut->setPageTitle( wfMsg('rollbackfailed') ); - $wgOut->addWikiText( wfMsg( 'alreadyrolled', - htmlspecialchars( $this->mTitle->getPrefixedText()), - htmlspecialchars( $from ), - htmlspecialchars( $current->getUserText() ) ) ); - if( $current->getComment() != '') { - $wgOut->addHTML( - wfMsg( 'editcomment', - $wgUser->getSkin()->formatComment( $current->getComment() ) ) ); - } - return; + $resultDetails = array( 'current' => $current ); + return self::ALREADY_ROLLED; } # Get the last edit not by this guy @@ -2222,11 +2231,9 @@ class Article { ); if( $s === false ) { # Something wrong - $wgOut->setPageTitle(wfMsg('rollbackfailed')); - $wgOut->addHTML( wfMsg( 'cantrollback' ) ); - return; + return self::ONLY_AUTHOR; } - + $set = array(); if ( $bot ) { # Mark all reverted edits as bot @@ -2239,27 +2246,100 @@ class Article { if ( $set ) { $dbw->update( 'recentchanges', $set, - array( /* WHERE */ - 'rc_cur_id' => $current->getPage(), - 'rc_user_text' => $current->getUserText(), - "rc_timestamp > '{$s->rev_timestamp}'", - ), __METHOD__ - ); + array( /* WHERE */ + 'rc_cur_id' => $current->getPage(), + 'rc_user_text' => $current->getUserText(), + "rc_timestamp > '{$s->rev_timestamp}'", + ), __METHOD__ + ); } # Get the edit summary $target = Revision::newFromId( $s->rev_id ); - $newComment = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); - $newComment = $wgRequest->getText( 'summary', $newComment ); + if( empty( $summary ) ) + $summary = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); + + # Save + $flags = EDIT_UPDATE | EDIT_MINOR; + if( $bot ) + $flags |= EDIT_FORCE_BOT; + $this->doEdit( $target->getText(), $summary, $flags ); + + $resultDetails = array( + 'summary' => $summary, + 'current' => $current, + 'target' => $target, + ); + return self::SUCCESS; + } - # Save it! - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); - $wgOut->setRobotpolicy( 'noindex,nofollow' ); - $wgOut->addHTML( '

' . htmlspecialchars( $newComment ) . "

\n
\n" ); + /** + * User interface for rollback operations + */ + function rollback() { + global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; - $this->updateArticle( $target->getText(), $newComment, 1, $this->mTitle->userIsWatching(), $bot ); + $details = null; + $result = $this->doRollback( + $wgRequest->getVal( 'from' ), + $wgRequest->getText( 'summary' ), + $wgRequest->getVal( 'token' ), + $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::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 `{$retval}`" ); + } - $wgOut->returnToMain( false ); } @@ -2317,7 +2397,7 @@ class Article { if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) { wfSeedRandom(); - if ( 0 == mt_rand( 0, 999 ) ) { + if ( 0 == mt_rand( 0, 99 ) ) { # Periodically flush old entries from the recentchanges table. global $wgRCMaxAge; @@ -2982,6 +3062,4 @@ class Article { $wgOut->addParserOutput( $parserOutput ); } -} - -?> +} \ No newline at end of file