From 075396a961140c3ae7baf27238f6a7a0d79757cc Mon Sep 17 00:00:00 2001 From: Arne Heizmann Date: Mon, 9 Aug 2004 05:38:11 +0000 Subject: [PATCH] New feature: Recent Changes Patrol. All edits and new pages are now highlighted on Special:Recentchanges and Special:Newpages until someone "marks" them as "patrolled" using a special link. For new pages, this link appears at the bottom of the article if the link in Recent Changes or New Pages is followed. For all other edits, this link appears only in the diff and only if the diff link is followed from Recent Changes. (Might need to add this functionality to Watchlist too; haven't done that yet.) --- includes/Article.php | 192 ++++++++++++++--------- includes/DifferenceEngine.php | 138 ++++++++-------- includes/QueryPage.php | 45 +++--- includes/RecentChange.php | 88 +++++++---- includes/Skin.php | 47 +++--- includes/SpecialNewpages.php | 22 ++- includes/SpecialRecentchanges.php | 66 ++++---- languages/Language.php | 21 ++- maintenance/archives/patch-rc-patrol.sql | 9 ++ maintenance/tables.sql | 5 +- stylesheets/monobook/main.css | 8 + 11 files changed, 372 insertions(+), 269 deletions(-) create mode 100755 maintenance/archives/patch-rc-patrol.sql diff --git a/includes/Article.php b/includes/Article.php index 319166cc95..d56a0005e6 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -224,7 +224,7 @@ class Article { $action=='view' ) { wfProfileOut( $fname ); - return $this->mContent . "\n" .wfMsg('anontalkpagetext'); + return $this->mContent . "\n" .wfMsg('anontalkpagetext'); } else { if($action=='edit') { if($section!='') { @@ -324,12 +324,12 @@ class Article { function &getOldContentFields() { global $wgArticleOldContentFields; if ( !$wgArticleOldContentFields ) { - $wgArticleOldContentFields = array( 'old_namespace','old_title','old_text','old_timestamp', + $wgArticleOldContentFields = array( 'old_namespace','old_title','old_text','old_timestamp', 'old_user','old_user_text','old_comment','old_flags' ); } return $wgArticleOldContentFields; } - + # Load the revision (including cur_text) into this object function loadContent( $noredir = false ) { @@ -362,7 +362,7 @@ class Article { if ( 0 == $id ) return; $s = $dbr->getArray( 'cur', $this->getCurContentFields(), array( 'cur_id' => $id ), $fname ); - if ( $s === false ) { + if ( $s === false ) { return; } @@ -448,7 +448,7 @@ class Article { } $s = $dbr->getArray( 'cur', $this->getCurContentFields(), array( 'cur_id' => $id ), $fname ); - if ( $s === false ) { + if ( $s === false ) { return false; } @@ -481,7 +481,7 @@ class Article { $this->mTitle->mRestrictionsLoaded = true; } else { # oldid set, retrieve historical version $s = $dbr->getArray( 'old', $this->getOldContentFields(), array( 'old_id' => $oldid ) ); - if ( $s === false ) { + if ( $s === false ) { return false; } $this->mContent = Article::getRevisionText( $s ); @@ -534,11 +534,11 @@ class Article { { global $wgOut; if ( -1 != $this->mUser ) return; - + $fname = 'Article::loadLastEdit'; $dbr =& wfGetDB( DB_SLAVE ); - $s = $dbr->getArray( 'cur', + $s = $dbr->getArray( 'cur', array( 'cur_user','cur_user_text','cur_timestamp', 'cur_comment','cur_minor_edit' ), array( 'cur_id' => $this->getID() ), $fname ); @@ -597,11 +597,11 @@ class Article { $user = $this->getUser(); $sql = "SELECT old_user, old_user_text, user_real_name, MAX(old_timestamp) as timestamp - FROM $oldTable LEFT JOIN $userTable ON old_user = user_id + FROM $oldTable LEFT JOIN $userTable ON old_user = user_id WHERE old_namespace = $user AND old_title = $encDBkey AND old_user != $user - GROUP BY old_user + GROUP BY old_user ORDER BY timestamp DESC"; if ($limit > 0) { @@ -624,15 +624,17 @@ class Article { function view() { - global $wgUser, $wgOut, $wgLang, $wgRequest, $wgMwRedir; + global $wgUser, $wgOut, $wgLang, $wgRequest, $wgMwRedir, $wgOnlySysopsCanPatrol; global $wgLinkCache, $IP, $wgEnableParserCache, $wgStylePath; + $sk = $wgUser->getSkin(); $fname = 'Article::view'; wfProfileIn( $fname ); - # Get variables from query string :P + # Get variables from query string $oldid = $wgRequest->getVal( 'oldid' ); $diff = $wgRequest->getVal( 'diff' ); + $rcid = $wgRequest->getVal( 'rcid' ); $wgOut->setArticleFlag( true ); $wgOut->setRobotpolicy( 'index,follow' ); @@ -642,7 +644,7 @@ class Article { if ( !is_null( $diff ) ) { $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); - $de = new DifferenceEngine( intval($oldid), intval($diff) ); + $de = new DifferenceEngine( intval($oldid), intval($diff), intval($rcid) ); $de->showDiffPage(); wfProfileOut( $fname ); if( $diff == 0 ) { @@ -715,7 +717,6 @@ class Article { $wgOut->addHTML( '
'.htmlspecialchars($this->mContent)."\n
" ); } else if ( $rt = Title::newFromRedirect( $text ) ) { # Display redirect - $sk = $wgUser->getSkin(); $imageUrl = "$wgStylePath/images/redirect.png"; $targetUrl = $rt->escapeLocalURL(); $titleText = htmlspecialchars( $rt->getPrefixedText() ); @@ -732,6 +733,17 @@ class Article { } $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); + # If we have been passed an &rcid= parameter, we want to give the user a + # chance to mark this new article as patrolled. + if ( !is_null ( $rcid ) && $rcid != 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + { + $wgOut->addHTML( wfMsg ( 'markaspatrolledlink', + $sk->makeKnownLinkObj ( $this->mTitle, wfMsg ( 'markaspatrolledtext' ), + "action=markpatrolled&rcid={$rcid}" ) + ) ); + } + # Add link titles as META keywords $wgOut->addMetaTags() ; @@ -765,7 +777,7 @@ class Article { $rand = number_format( mt_rand() / mt_getrandmax(), 12, '.', '' ); $dbw =& wfGetDB( DB_MASTER ); - $cur_id = $dbw->nextSequenceValue( 'cur_cur_id_seq' ); + $cur_id = $dbw->nextSequenceValue( 'cur_cur_id_seq' ); $isminor = ( $isminor && $wgUser->getID() ) ? 1 : 0; @@ -894,10 +906,10 @@ class Article { global $wgOut, $wgUser; global $wgDBtransactions, $wgMwRedir; global $wgUseSquid, $wgInternalServer; - + $fname = 'Article::updateArticle'; $good = true; - + if ( $this->mMinorEdit ) { $me1 = 1; } else { $me1 = 0; } if ( $minor && $wgUser->getID() ) { $me2 = 1; } else { $me2 = 0; } if ( preg_match( "/^((" . $wgMwRedir->getBaseRegex() . ')[^\\n]+)/i', $text, $m ) ) { @@ -911,15 +923,15 @@ class Article { # Update article, but only if changed. - # It's important that we either rollback or complete, otherwise an attacker could - # overwrite cur entries by sending precisely timed user aborts. Random bored users + # It's important that we either rollback or complete, otherwise an attacker could + # overwrite cur entries by sending precisely timed user aborts. Random bored users # could conceivably have the same effect, especially if cur is locked for long periods. if( $wgDBtransactions ) { $dbw->query( 'BEGIN', $fname ); } else { $userAbort = ignore_user_abort( true ); } - + $oldtext = $this->getContent( true ); if ( 0 != strcmp( $text, $oldtext ) ) { @@ -929,24 +941,24 @@ class Article { $won = wfInvertTimestamp( $now ); # First update the cur row - $dbw->updateArray( 'cur', - array( /* SET */ + $dbw->updateArray( 'cur', + array( /* SET */ 'cur_text' => $text, 'cur_comment' => $summary, - 'cur_minor_edit' => $me2, + 'cur_minor_edit' => $me2, 'cur_user' => $wgUser->getID(), 'cur_timestamp' => $now, 'cur_user_text' => $wgUser->getName(), - 'cur_is_redirect' => $redir, + 'cur_is_redirect' => $redir, 'cur_is_new' => 0, - 'cur_touched' => $now, + 'cur_touched' => $now, 'inverse_timestamp' => $won ), array( /* WHERE */ - 'cur_id' => $this->getID(), - 'cur_timestamp' => $this->getTimestamp() - ), $fname + 'cur_id' => $this->getID(), + 'cur_timestamp' => $this->getTimestamp() + ), $fname ); - + if( $dbw->affectedRows() == 0 ) { /* Belated edit conflict! Run away!! */ $good = false; @@ -955,8 +967,8 @@ class Article { # This overwrites $oldtext if revision compression is on $flags = Article::compressRevisionText( $oldtext ); - - $dbw->insertArray( 'old', + + $dbw->insertArray( 'old', array( 'old_id' => $dbw->nextSequenceValue( 'old_old_id_seq' ), 'old_namespace' => $this->mTitle->getNamespace(), @@ -969,13 +981,13 @@ class Article { 'old_minor_edit' => $me1, 'inverse_timestamp' => wfInvertTimestamp( $this->getTimestamp() ), 'old_flags' => $flags, - ), $fname + ), $fname ); - + $oldid = $dbw->insertId(); $bot = (int)($wgUser->isBot() || $forceBot); - RecentChange::notifyEdit( $now, $this->mTitle, $me2, $wgUser, $summary, + RecentChange::notifyEdit( $now, $this->mTitle, $me2, $wgUser, $summary, $oldid, $this->getTimestamp(), $bot ); Article::onArticleEdit( $this->mTitle ); } @@ -1035,15 +1047,15 @@ class Article { $wgLinkCache = new LinkCache(); # Select for update $wgLinkCache->forUpdate( true ); - + # Get old version of link table to allow incremental link updates $wgLinkCache->preFill( $this->mTitle ); $wgLinkCache->clear(); - + # Switch on use of link cache in the skin $sk =& $wgUser->getSkin(); $sk->postParseLinkColour( false ); - + # Now update the link cache by parsing the text $wgOut = new OutputPage(); $wgOut->addWikiText( $text ); @@ -1056,7 +1068,7 @@ class Article { } # Validate article - + function validate () { global $wgOut ; @@ -1068,11 +1080,35 @@ class Article { return ; } $v = new Validation ; - $v->validate_form ( $this->mTitle->getDBkey() ) ; + $v->validate_form ( $this->mTitle->getDBkey() ) ; } - # Add this page to my watchlist + # Mark this particular edit as patrolled + function markpatrolled() + { + global $wgOut, $wgRequest, $wgOnlySysopsCanPatrol; + $wgOut->setRobotpolicy( 'noindex,follow' ); + if( $wgOnlySysopsCanPatrol && !$wgUser->isSysop() ) + { + $wgOut->sysopRequired(); + return; + } + $rcid = $wgRequest->getVal( 'rcid' ); + if ( !is_null ( $rcid ) ) + { + RecentChange::markPatrolled( $rcid ); + $wgOut->setPagetitle( wfMsg( 'markedaspatrolled' ) ); + $wgOut->addWikiText( wfMsg( 'markedaspatrolledtext' ) ); + $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); + } + else + { + $wgOut->errorpage( 'markedaspatrollederror', 'markedaspatrollederrortext' ); + } + } + + # Add this page to my watchlist function watch( $add = true ) { global $wgUser, $wgOut, $wgLang; @@ -1137,13 +1173,13 @@ class Article { if ( $confirm ) { $dbw =& wfGetDB( DB_MASTER ); - $dbw->updateArray( 'cur', + $dbw->updateArray( 'cur', array( /* SET */ 'cur_touched' => wfTimestampNow(), 'cur_restrictions' => (string)$limit ), array( /* WHERE */ - 'cur_id' => $id - ), 'Article::protect' + 'cur_id' => $id + ), 'Article::protect' ); $log = new LogPage( wfMsg( 'protectlogpage' ), wfMsg( 'protectlogtext' ) ); @@ -1269,29 +1305,29 @@ class Article { $dbr =& wfGetDB( DB_SLAVE ); $ns = $this->mTitle->getNamespace(); $title = $this->mTitle->getDBkey(); - $old = $dbr->getArray( 'old', - array( 'old_text', 'old_flags' ), + $old = $dbr->getArray( 'old', + array( 'old_text', 'old_flags' ), array( 'old_namespace' => $ns, 'old_title' => $title, - ), $fname, array( 'ORDER BY' => 'inverse_timestamp' ) + ), $fname, array( 'ORDER BY' => 'inverse_timestamp' ) ); - + if( $old !== false && !$confirm ) { $skin=$wgUser->getSkin(); $wgOut->addHTML(''.wfMsg('historywarning')); $wgOut->addHTML( $skin->historyLink() .''); } - + # Fetch cur_text - $s = $dbr->getArray( 'cur', - array( 'cur_text' ), - array( - 'cur_namespace' => $ns, + $s = $dbr->getArray( 'cur', + array( 'cur_text' ), + array( + 'cur_namespace' => $ns, 'cur_title' => $title, ), $fname ); - + if( $s !== false ) { # if this is a mini-text, we can paste part of it into the deletion reason @@ -1426,7 +1462,7 @@ class Article { $fname = 'Article::doDeleteArticle'; wfDebug( $fname."\n" ); - + $dbw =& wfGetDB( DB_MASTER ); $ns = $this->mTitle->getNamespace(); $t = $this->mTitle->getDBkey(); @@ -1466,8 +1502,8 @@ class Article { $recentchangesTable = $dbw->tableName( 'recentchanges' ); $linksTable = $dbw->tableName( 'links' ); $brokenlinksTable = $dbw->tableName( 'brokenlinks' ); - - $dbw->insertSelect( 'archive', 'cur', + + $dbw->insertSelect( 'archive', 'cur', array( 'ar_namespace' => 'cur_namespace', 'ar_title' => 'cur_title', @@ -1481,9 +1517,9 @@ class Article { ), array( 'cur_namespace' => $ns, 'cur_title' => $t, - ), $fname + ), $fname ); - + $dbw->insertSelect( 'archive', 'old', array( 'ar_namespace' => 'old_namespace', @@ -1500,7 +1536,7 @@ class Article { 'old_title' => $t, ), $fname ); - + # Now that it's safely backed up, delete it $dbw->delete( 'cur', array( 'cur_namespace' => $ns, 'cur_title' => $t ), $fname ); @@ -1520,7 +1556,7 @@ class Article { $brokenLinks[] = array( 'bl_from' => $linkID, 'bl_to' => $t ); } $dbw->insert( 'brokenlinks', $brokenLinks, $fname, 'IGNORE' ); - + # Delete live links $dbw->delete( 'links', array( 'l_to' => $id ) ); $dbw->delete( 'links', array( 'l_from' => $id ) ); @@ -1543,7 +1579,7 @@ class Article { { global $wgUser, $wgLang, $wgOut, $wgRequest; $fname = "Article::rollback"; - + if ( ! $wgUser->isSysop() ) { $wgOut->sysopRequired(); return; @@ -1562,7 +1598,7 @@ class Article { $n = $this->mTitle->getNamespace(); # Get the last editor, lock table exclusively - $s = $dbw->getArray( 'cur', + $s = $dbw->getArray( 'cur', array( 'cur_id','cur_user','cur_user_text','cur_comment' ), array( 'cur_title' => $tt, 'cur_namespace' => $n ), $fname, 'FOR UPDATE' @@ -1592,10 +1628,10 @@ class Article { } # Get the last edit not by this guy - $s = $dbw->getArray( 'old', + $s = $dbw->getArray( 'old', array( 'old_text','old_user','old_user_text','old_timestamp','old_flags' ), - array( - 'old_namespace' => $n, + array( + 'old_namespace' => $n, 'old_title' => $tt, "old_user <> {$uid} OR old_user_text <> '{$ut}'" ), $fname, array( 'FOR UPDATE', 'USE INDEX' => 'name_title_timestamp' ) @@ -1609,13 +1645,13 @@ class Article { if ( $bot ) { # Mark all reverted edits as bot - $dbw->updateArray( 'recentchanges', - array( /* SET */ - 'rc_bot' => 1 + $dbw->updateArray( 'recentchanges', + array( /* SET */ + 'rc_bot' => 1 ), array( /* WHERE */ 'rc_user' => $uid, "rc_timestamp > '{$s->old_timestamp}'", - ), $fname + ), $fname ); } @@ -1655,7 +1691,7 @@ class Article { { global $wgDeferredUpdateList, $wgDBname, $wgMemc; global $wgMessageCache; - + wfSeedRandom(); if ( 0 == mt_rand( 0, 999 ) ) { $dbw =& wfGetDB( DB_MASTER ); @@ -1762,7 +1798,7 @@ class Article { $id = $this->getID(); $dbr =& wfGetDB( DB_SLAVE ); - $s = $dbr->getArray( 'cur', array( 'cur_touched', 'cur_is_redirect' ), + $s = $dbr->getArray( 'cur', array( 'cur_touched', 'cur_is_redirect' ), array( 'cur_id' => $id ), $fname ); if( $s !== false ) { $this->mTouched = $s->cur_touched; @@ -1798,7 +1834,7 @@ class Article { ), array( 'cur_namespace' => $ns, 'cur_title' => $dbkey, - ), $fname + ), $fname ); # Use the affected row count to determine if the article is new @@ -1841,14 +1877,14 @@ class Article { $curTable = $dbw->tableName( 'cur' ); $hitcounterTable = $dbw->tableName( 'hitcounter' ); $acchitsTable = $dbw->tableName( 'acchits' ); - + if( $wgHitcounterUpdateFreq <= 1 ){ // $dbw->query( "UPDATE $curTable SET cur_counter = cur_counter + 1 WHERE cur_id = $id" ); return; } # Not important enough to warrant an error page in case of failure - $oldignore = $dbw->ignoreErrors( true ); + $oldignore = $dbw->ignoreErrors( true ); $dbw->query( "INSERT INTO $hitcounterTable (hc_id) VALUES ({$id})" ); @@ -1922,12 +1958,12 @@ class Article { { global $wgUser, $wgTitle, $wgOut, $wgLang, $wgAllowPageInfo; $fname = 'Article::info'; - + if ( !$wgAllowPageInfo ) { $wgOut->errorpage( "nosuchaction", "nosuchactiontext" ); return; } - + $dbr =& wfGetDB( DB_SLAVE ); $basenamespace = $wgTitle->getNamespace() & (~1); @@ -1957,7 +1993,7 @@ class Article { $cur_author = $dbr->selectField( 'cur', 'cur_user_text', $cur_clause, $fname ); # find number of 'old' authors excluding 'cur' author - $authors = $dbr->selectField( 'old', 'COUNT(DISTINCT old_user_text)', + $authors = $dbr->selectField( 'old', 'COUNT(DISTINCT old_user_text)', $old_clause + array( 'old_user_text<>' . $dbr->addQuotes( $cur_author ) ), $fname ) + 1; # now for the Talk page ... @@ -1977,7 +2013,7 @@ class Article { # number of authors if ($exists > 0) { $cur_author = $dbr->selectField( 'cur', 'cur_user_text', $cur_clause, $fname ); - $authors = $dbr->selectField( 'cur', 'COUNT(DISTINCT old_user_text)', + $authors = $dbr->selectField( 'cur', 'COUNT(DISTINCT old_user_text)', $old_clause + array( 'old_user_text<>' . $dbr->addQuotes( $cur_author ) ), $fname ); $wgOut->addHTML( "
  • " . wfMsg("numtalkauthors", $authors) . "
  • " ); diff --git a/includes/DifferenceEngine.php b/includes/DifferenceEngine.php index 8b80c27e8b..c2c388467f 100644 --- a/includes/DifferenceEngine.php +++ b/includes/DifferenceEngine.php @@ -8,19 +8,21 @@ class DifferenceEngine { /* private */ var $mOldUser, $mNewUser; /* private */ var $mOldComment, $mNewComment; /* private */ var $mOldPage, $mNewPage; - - function DifferenceEngine( $old, $new ) + /* private */ var $mRcidMarkPatrolled; + + function DifferenceEngine( $old, $new, $rcid = 0 ) { $this->mOldid = $old; $this->mNewid = $new; + $this->mRcidMarkPatrolled = intval($rcid); # force it to be an integer } function showDiffPage() { - global $wgUser, $wgTitle, $wgOut, $wgLang; + global $wgUser, $wgTitle, $wgOut, $wgLang, $wgOnlySysopsCanPatrol; $fname = "DifferenceEngine::showDiffPage"; wfProfileIn( $fname ); - + $t = $wgTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " . "{$this->mNewid})"; $mtext = wfMsg( "missingarticle", $t ); @@ -33,7 +35,7 @@ class DifferenceEngine { return; } $wgOut->suppressQuickbar(); - + $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if( $oldTitle == $newTitle ) { @@ -43,7 +45,7 @@ class DifferenceEngine { } $wgOut->setSubtitle( wfMsg( "difference" ) ); $wgOut->setRobotpolicy( "noindex,follow" ); - + if ( !( $this->mOldPage->userCanRead() && $this->mNewPage->userCanRead() ) ) { $wgOut->loginToUse(); $wgOut->output(); @@ -55,11 +57,9 @@ class DifferenceEngine { $talk = $wgLang->getNsText( NS_TALK ); $contribs = wfMsg( "contribslink" ); - $this->mOldComment = $sk->formatComment($this->mOldComment); $this->mNewComment = $sk->formatComment($this->mNewComment); - $oldUserLink = $sk->makeLinkObj( Title::makeTitle( NS_USER, $this->mOldUser ), $this->mOldUser ); $newUserLink = $sk->makeLinkObj( Title::makeTitle( NS_USER, $this->mNewUser ), $this->mNewUser ); $oldUTLink = $sk->makeLinkObj( Title::makeTitle( NS_USER_TALK, $this->mOldUser ), $talk ); @@ -74,17 +74,25 @@ class DifferenceEngine { } else { $rollback = ""; } + if ( $this->mRcidMarkPatrolled != 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + { + $patrol = " [" . $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'markaspatrolleddiff' ), + "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}" ) . "]"; + } else { + $patrol = ""; + } - $oldHeader = "{$this->mOldtitle}
    $oldUserLink ($oldUTLink | $oldContribs)
    ". - $this->mOldComment; - $newHeader = "{$this->mNewtitle}
    $newUserLink ($newUTLink | $newContribs) $rollback
    ". - $this->mNewComment; + $oldHeader = "{$this->mOldtitle}
    $oldUserLink " . + "($oldUTLink | $oldContribs)
    " . $this->mOldComment; + $newHeader = "{$this->mNewtitle}
    $newUserLink " . + "($newUTLink | $newContribs) $rollback
    " . $this->mNewComment . $patrol; DifferenceEngine::showDiff( $this->mOldtext, $this->mNewtext, $oldHeader, $newHeader ); $wgOut->addHTML( "

    {$this->mNewtitle}

    \n" ); $wgOut->addWikiText( $this->mNewtext ); - + wfProfileOut( $fname ); } @@ -125,17 +133,17 @@ cellpadding='0' cellspacing='4px' class='diff'> { global $wgTitle, $wgOut, $wgLang; $fname = "DifferenceEngine::loadText"; - + $dbr =& wfGetDB( DB_SLAVE ); if ( 0 == $this->mNewid || 0 == $this->mOldid ) { $wgOut->setArticleFlag( true ); $this->mNewtitle = wfMsg( "currentrev" ); $id = $wgTitle->getArticleID(); - - $s = $dbr->getArray( 'cur', array( 'cur_text', 'cur_user_text', 'cur_comment' ), + + $s = $dbr->getArray( 'cur', array( 'cur_text', 'cur_user_text', 'cur_comment' ), array( 'cur_id' => $id ), $fname ); - if ( $s === false ) { - return false; + if ( $s === false ) { + return false; } $this->mNewPage = &$wgTitle; @@ -146,8 +154,8 @@ cellpadding='0' cellspacing='4px' class='diff'> $s = $dbr->getArray( 'old', array( 'old_namespace','old_title','old_timestamp', 'old_text', 'old_flags','old_user_text','old_comment' ), array( 'old_id' => $this->mNewid ), $fname ); - if ( $s === false ) { - return false; + if ( $s === false ) { + return false; } $this->mNewtext = Article::getRevisionText( $s ); @@ -159,22 +167,22 @@ cellpadding='0' cellspacing='4px' class='diff'> $this->mNewComment = $s->old_comment; } if ( 0 == $this->mOldid ) { - $s = $dbr->getArray( 'old', - array( 'old_namespace','old_title','old_timestamp','old_text', 'old_flags','old_user_text','old_comment' ), + $s = $dbr->getArray( 'old', + array( 'old_namespace','old_title','old_timestamp','old_text', 'old_flags','old_user_text','old_comment' ), array( /* WHERE */ - 'old_namespace' => $this->mNewPage->getNamespace(), - 'old_title' => $this->mNewPage->getDBkey() + 'old_namespace' => $this->mNewPage->getNamespace(), + 'old_title' => $this->mNewPage->getDBkey() ), $fname, array( 'ORDER BY' => 'inverse_timestamp', 'USE INDEX' => 'name_title_timestamp' ) ); } else { - $s = $dbr->getArray( 'old', + $s = $dbr->getArray( 'old', array( 'old_namespace','old_title','old_timestamp','old_text','old_flags','old_user_text','old_comment'), - array( 'old_id' => $this->mOldid ), + array( 'old_id' => $this->mOldid ), $fname ); } - if ( $s === false ) { - return false; + if ( $s === false ) { + return false; } $this->mOldPage = Title::MakeTitle( $s->old_namespace, $s->old_title ); $this->mOldtext = Article::getRevisionText( $s ); @@ -183,7 +191,7 @@ cellpadding='0' cellspacing='4px' class='diff'> $this->mOldtitle = wfMsg( "revisionasof", $t ); $this->mOldUser = $s->old_user_text; $this->mOldComment = $s->old_comment; - + return true; } } @@ -200,7 +208,7 @@ class _DiffOp { var $type; var $orig; var $closing; - + function reverse() { trigger_error("pure virtual", E_USER_ERROR); } @@ -216,7 +224,7 @@ class _DiffOp { class _DiffOp_Copy extends _DiffOp { var $type = 'copy'; - + function _DiffOp_Copy ($orig, $closing = false) { if (!is_array($closing)) $closing = $orig; @@ -231,7 +239,7 @@ class _DiffOp_Copy extends _DiffOp { class _DiffOp_Delete extends _DiffOp { var $type = 'delete'; - + function _DiffOp_Delete ($lines) { $this->orig = $lines; $this->closing = false; @@ -244,7 +252,7 @@ class _DiffOp_Delete extends _DiffOp { class _DiffOp_Add extends _DiffOp { var $type = 'add'; - + function _DiffOp_Add ($lines) { $this->closing = $lines; $this->orig = false; @@ -257,7 +265,7 @@ class _DiffOp_Add extends _DiffOp { class _DiffOp_Change extends _DiffOp { var $type = 'change'; - + function _DiffOp_Change ($orig, $closing) { $this->orig = $orig; $this->closing = $closing; @@ -267,8 +275,8 @@ class _DiffOp_Change extends _DiffOp { return new _DiffOp_Change($this->closing, $this->orig); } } - - + + /** * Class used internally by Diff to actually compute the diffs. * @@ -301,7 +309,7 @@ class _DiffEngine unset($this->seq); unset($this->in_seq); unset($this->lcs); - + // Skip leading common lines. for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) { if ($from_lines[$skip] != $to_lines[$skip]) @@ -315,7 +323,7 @@ class _DiffEngine break; $this->xchanged[$xi] = $this->ychanged[$yi] = false; } - + // Ignore lines which do not exist in both files. for ($xi = $skip; $xi < $n_from - $endskip; $xi++) $xhash[$from_lines[$xi]] = 1; @@ -367,7 +375,7 @@ class _DiffEngine $add = array(); while ($yi < $n_to && $this->ychanged[$yi]) $add[] = $to_lines[$yi++]; - + if ($delete && $add) $edits[] = new _DiffOp_Change($delete, $add); elseif ($delete) @@ -377,7 +385,7 @@ class _DiffEngine } return $edits; } - + /* Divide the Largest Common Subsequence (LCS) of the sequences * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally @@ -397,7 +405,7 @@ class _DiffEngine */ function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) { $flip = false; - + if ($xlim - $xoff > $ylim - $yoff) { // Things seems faster (I'm not sure I understand why) // when the shortest sequence in X. @@ -417,7 +425,7 @@ class _DiffEngine $this->seq[0]= $yoff - 1; $this->in_seq = array(); $ymids[0] = array(); - + $numer = $xlim - $xoff + $nchunks - 1; $x = $xoff; for ($chunk = 0; $chunk < $nchunks; $chunk++) { @@ -584,14 +592,14 @@ class _DiffEngine */ while ($j < $other_len && $other_changed[$j]) $j++; - + while ($i < $len && ! $changed[$i]) { USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]'); $i++; $j++; while ($j < $other_len && $other_changed[$j]) $j++; } - + if ($i == $len) break; @@ -673,7 +681,7 @@ class _DiffEngine /** * Class representing a 'diff' between two sequences of strings. */ -class Diff +class Diff { var $edits; @@ -722,7 +730,7 @@ class Diff } return true; } - + /** * Compute the length of the Longest Common Subsequence (LCS). * @@ -749,7 +757,7 @@ class Diff */ function orig() { $lines = array(); - + foreach ($this->edits as $edit) { if ($edit->orig) array_splice($lines, sizeof($lines), 0, $edit->orig); @@ -767,7 +775,7 @@ class Diff */ function closing() { $lines = array(); - + foreach ($this->edits as $edit) { if ($edit->closing) array_splice($lines, sizeof($lines), 0, $edit->closing); @@ -776,7 +784,7 @@ class Diff } /** - * Check a Diff for validity. + * Check a Diff for validity. * * This is here only for debugging purposes. */ @@ -804,7 +812,7 @@ class Diff trigger_error("Diff okay: LCS = $lcs", E_USER_NOTICE); } } - + /** * FIXME: bad name. */ @@ -839,7 +847,7 @@ extends Diff assert(sizeof($from_lines) == sizeof($mapped_from_lines)); assert(sizeof($to_lines) == sizeof($mapped_to_lines)); - + $this->Diff($mapped_from_lines, $mapped_to_lines); $xi = $yi = 0; @@ -849,7 +857,7 @@ extends Diff $orig = array_slice($from_lines, $xi, sizeof($orig)); $xi += sizeof($orig); } - + $closing = &$this->edits[$i]->closing; if (is_array($closing)) { $closing = array_slice($to_lines, $yi, sizeof($closing)); @@ -981,11 +989,11 @@ class DiffFormatter return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; } - + function _start_block($header) { echo $header; } - + function _end_block() { } @@ -993,7 +1001,7 @@ class DiffFormatter foreach ($lines as $line) echo "$prefix $line\n"; } - + function _context($lines) { $this->_lines($lines); } @@ -1015,7 +1023,7 @@ class DiffFormatter /** * Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3 - * + * */ define('NBSP', ' '); // iso-8859-x non-breaking space. @@ -1030,7 +1038,7 @@ class _HWLDF_WordAccumulator { function _flushGroup ($new_tag) { if ($this->_group !== '') { - if ($this->_tag == 'mark') + if ($this->_tag == 'mark') $this->_line .= ''.$this->_group.''; else $this->_line .= $this->_group; @@ -1038,14 +1046,14 @@ class _HWLDF_WordAccumulator { $this->_group = ''; $this->_tag = $new_tag; } - + function _flushLine ($new_tag) { $this->_flushGroup($new_tag); if ($this->_line != '') $this->_lines[] = $this->_line; $this->_line = ''; } - + function addWords ($words, $tag = '') { if ($tag != $this->_tag) $this->_flushGroup($tag); @@ -1076,7 +1084,7 @@ class WordLevelDiff extends MappedDiff list ($orig_words, $orig_stripped) = $this->_split($orig_lines); list ($closing_words, $closing_stripped) = $this->_split($closing_lines); - + $this->MappedDiff($orig_words, $closing_words, $orig_stripped, $closing_stripped); } @@ -1094,7 +1102,7 @@ class WordLevelDiff extends MappedDiff function orig () { $orig = new _HWLDF_WordAccumulator; - + foreach ($this->edits as $edit) { if ($edit->type == 'copy') $orig->addWords($edit->orig); @@ -1106,7 +1114,7 @@ class WordLevelDiff extends MappedDiff function closing () { $closing = new _HWLDF_WordAccumulator; - + foreach ($this->edits as $edit) { if ($edit->type == 'copy') $closing->addWords($edit->closing); @@ -1119,7 +1127,7 @@ class WordLevelDiff extends MappedDiff /** * Wikipedia Table style diff formatter. - * + * */ class TableDiffFormatter extends DiffFormatter { @@ -1127,7 +1135,7 @@ class TableDiffFormatter extends DiffFormatter $this->leading_context_lines = 2; $this->trailing_context_lines = 2; } - + function _block_header( $xbeg, $xlen, $ybeg, $ylen ) { $l1 = wfMsg( "lineno", $xbeg ); $l2 = wfMsg( "lineno", $ybeg ); @@ -1165,7 +1173,7 @@ class TableDiffFormatter extends DiffFormatter function contextLine( $line ) { return ' '.$line.''; } - + function _added($lines) { global $wgOut; foreach ($lines as $line) { diff --git a/includes/QueryPage.php b/includes/QueryPage.php index e6173ad99f..fb5dea8c12 100644 --- a/includes/QueryPage.php +++ b/includes/QueryPage.php @@ -27,7 +27,7 @@ class QueryPage { function getSQL() { return "SELECT 'sample' as type, 0 as namespace, 'Sample result' as title, 42 as value"; } - + # Override to sort by increasing values function sortDescending() { return true; @@ -55,10 +55,10 @@ class QueryPage { function formatResult( $skin, $result ) { return ""; } - + # This is the actual workhorse. It does everything needed to make a # real, honest-to-gosh query page. - + function doQuery( $offset, $limit ) { global $wgUser, $wgOut, $wgLang, $wgRequest; global $wgMiserMode; @@ -72,17 +72,17 @@ class QueryPage { $wgOut->setSyndicated( true ); $res = false; - + if ( $this->isExpensive() ) { $recache = $wgRequest->getBool( "recache" ); if( $recache ) { # Clear out any old cached data $dbw->delete( 'querycache', array( 'qc_type' => $sname ), $fname ); - + # Do query on the (possibly out of date) slave server $maxstored = 1000; $res = $dbr->query( $sql . $this->getOrderLimit( 0, $maxstored ), $fname ); - + # Fetch results $insertSql = "INSERT INTO $querycache (qc_type,qc_namespace,qc_title,qc_value) VALUES "; $first = true; @@ -91,7 +91,7 @@ class QueryPage { $first = false; } else { $insertSql .= ","; - } + } $insertSql .= "(" . $dbw->addQuotes( $row->type ) . "," . $dbw->addQuotes( $row->namespace ) . "," . @@ -125,8 +125,8 @@ class QueryPage { $res = $dbr->query( $sql . $this->getOrderLimit( $offset, $limit ), $fname ); $num = $dbr->numRows($res); } - - + + $sk = $wgUser->getSkin( ); $top = wfShowingResults( $offset, $num); @@ -134,22 +134,23 @@ class QueryPage { # often disable 'next' link when we reach the end if($num < $limit) { $atend = true; } else { $atend = false; } - + $sl = wfViewPrevNext( $offset, $limit , $wgLang->specialPage( $sname ), "" ,$atend ); $wgOut->addHTML( "
    {$sl}

    \n" ); - $s = "
      "; + $s = "
        "; # Only read at most $num rows, because $res may contain the whole 1000 for ( $i = 0; $i < $num && $obj = $dbr->fetchObject( $res ); $i++ ) { $format = $this->formatResult( $sk, $obj ); - $s .= "
      1. {$format}
      2. \n"; + $attr = ( $obj->usepatrol && $obj->patrolled == 0 ) ? ' class="not_patrolled"' : ''; + $s .= "{$format}\n"; } $dbr->freeResult( $res ); $s .= "
      "; $wgOut->addHTML( $s ); $wgOut->addHTML( "

      {$sl}

      \n" ); } - + # Similar to above, but packaging in a syndicated feed instead of a web page function doFeed( $class = "" ) { global $wgFeedClasses; @@ -160,7 +161,7 @@ class QueryPage { $this->feedDesc(), $this->feedUrl() ); $feed->outHeader(); - + $dbr =& wfGetDB( DB_SLAVE ); $sql = $this->getSQL() . $this->getOrderLimit( 0, 50 ); $res = $dbr->query( $sql, "QueryPage::doFeed" ); @@ -189,13 +190,13 @@ class QueryPage { } else { $date = ""; } - + $comments = ""; if( $title ) { $talkpage = $title->getTalkPage(); $comments = $talkpage->getFullURL(); } - + return new FeedItem( $title->getText(), $this->feedItemDesc( $row ), @@ -207,7 +208,7 @@ class QueryPage { return NULL; } } - + function feedItemDesc( $row ) { $text = ""; if( isset( $row->comment ) ) { @@ -215,14 +216,14 @@ class QueryPage { } else { $text = ""; } - + if( isset( $row->text ) ) { $text = "

      " . htmlspecialchars( wfMsg( "summary" ) ) . ": " . $text . "

      \n
      \n
      " . nl2br( htmlspecialchars( $row->text ) ) . "
      ";; } return $text; } - + function feedItemAuthor( $row ) { if( isset( $row->user_text ) ) { return $row->user_text; @@ -230,18 +231,18 @@ class QueryPage { return ""; } } - + function feedTitle() { global $wgLanguageCode, $wgSitename, $wgLang; $page = SpecialPage::getPage( $this->getName() ); $desc = $page->getDescription(); return "$wgSitename - $desc [$wgLanguageCode]"; } - + function feedDesc() { return wfMsg( "fromwikipedia" ); } - + function feedUrl() { global $wgLang; $title = Title::MakeTitle( NS_SPECIAL, $this->getName() ); diff --git a/includes/RecentChange.php b/includes/RecentChange.php index eb3aeb6361..dd0370e1f1 100644 --- a/includes/RecentChange.php +++ b/includes/RecentChange.php @@ -10,11 +10,12 @@ define( "RC_MOVE_OVER_REDIRECT", 4); /* mAttributes: + rc_id id of the row in the recentchanges table rc_timestamp time the entry was made rc_cur_time timestamp on the cur row rc_namespace namespace # rc_title non-prefixed db key - rc_type is new entry, used to determine whether updating is necessary + rc_type is new entry, used to determine whether updating is necessary rc_minor is minor rc_cur_id id of associated cur entry rc_user user id who made the entry @@ -25,6 +26,7 @@ mAttributes: rc_bot is bot, hidden rc_ip IP address of the user in dotted quad notation rc_new obsolete, use rc_type==RC_NEW + rc_patrolled boolean whether or not someone has marked this edit as patrolled mExtra: prefixedDBkey prefixed db key, used by external app via msg queue @@ -38,14 +40,14 @@ class RecentChange var $mTitle = false, $mMovedToTitle = false; # Factory methods - - /* static */ function newFromRow( $row ) + + /* static */ function newFromRow( $row ) { $rc = new RecentChange; $rc->loadFromRow( $row ); return $rc; } - + /* static */ function newFromCurRow( $row ) { $rc = new RecentChange; @@ -54,17 +56,17 @@ class RecentChange } # Accessors - - function setAttribs( $attribs ) + + function setAttribs( $attribs ) { $this->mAttribs = $attribs; } - + function setExtra( $extra ) { $this->mExtra = $extra; } - + function getTitle() { if ( $this->mTitle === false ) { @@ -76,31 +78,31 @@ class RecentChange function getMovedToTitle() { if ( $this->mMovedToTitle === false ) { - $this->mMovedToTitle = Title::makeTitle( $this->mAttribs['rc_moved_to_ns'], + $this->mMovedToTitle = Title::makeTitle( $this->mAttribs['rc_moved_to_ns'], $this->mAttribs['rc_moved_to_title'] ); } return $this->mMovedToTitle; } # Writes the data in this object to the database - function save() + function save() { global $wgUseRCQueue, $wgRCQueueID, $wgLocalInterwiki, $wgPutIPinRC; $fname = "RecentChange::save"; - + $dbw =& wfGetDB( DB_MASTER ); if ( !is_array($this->mExtra) ) { $this->mExtra = array(); } $this->mExtra['lang'] = $wgLocalInterwiki; - + if ( !$wgPutIPinRC ) { $this->mAttribs['rc_ip'] = ''; } - + # Insert new row $dbw->insertArray( "recentchanges", $this->mAttribs, $fname ); - + # Update old rows, if necessary if ( $this->mAttribs['rc_type'] == RC_EDIT ) { $oldid = $this->mAttribs['rc_last_oldid']; @@ -109,12 +111,12 @@ class RecentChange $lastTime = $this->mExtra['lastTimestamp']; $now = $this->mAttribs['rc_timestamp']; $curId = $this->mAttribs['rc_cur_id']; - + # Update rc_this_oldid for the entries which were current - $dbw->updateArray( 'recentchanges', + $dbw->updateArray( 'recentchanges', array( /* SET */ 'rc_this_oldid' => $oldid - ), array( /* WHERE */ + ), array( /* WHERE */ 'rc_namespace' => $ns, 'rc_title' => $title, 'rc_timestamp' => $lastTime @@ -122,24 +124,40 @@ class RecentChange ); # Update rc_cur_time - $dbw->updateArray( 'recentchanges', array( 'rc_cur_time' => $now ), + $dbw->updateArray( 'recentchanges', array( 'rc_cur_time' => $now ), array( 'rc_cur_id' => $curId ), $fname ); } - + # Notify external application if ( $wgUseRCQueue ) { $queue = msg_get_queue( $wgRCQueueID ); - if (!msg_send( $queue, array_merge( $this->mAttribs, 1, $this->mExtra ), - true, false, $error )) + if (!msg_send( $queue, array_merge( $this->mAttribs, 1, $this->mExtra ), + true, false, $error )) { wfDebug( "Error sending message to RC queue, code $error\n" ); } } } - + + # Marks a certain row as patrolled + function markPatrolled( $rcid ) + { + $fname = "RecentChange::markPatrolled"; + + $dbw =& wfGetDB( DB_MASTER ); + + $dbw->updateArray( 'recentchanges', + array( /* SET */ + 'rc_patrolled' => 1 + ), array( /* WHERE */ + 'rc_id' => $rcid + ), $fname + ); + } + # Makes an entry in the database corresponding to an edit - /*static*/ function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, - $oldId, $lastTimestamp, $bot = "default", $ip = '' ) + /*static*/ function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, + $oldId, $lastTimestamp, $bot = "default", $ip = '' ) { if ( $bot == "default " ) { $bot = $user->isBot(); @@ -149,7 +167,7 @@ class RecentChange global $wgIP; $ip = empty( $wgIP ) ? '' : $wgIP; } - + $rc = new RecentChange; $rc->mAttribs = array( 'rc_timestamp' => $timestamp, @@ -170,14 +188,14 @@ class RecentChange 'rc_ip' => $ip, 'rc_new' => 0 # obsolete ); - + $rc->mExtra = array( 'prefixedDBkey' => $title->getPrefixedDBkey(), 'lastTimestamp' => $lastTimestamp ); $rc->save(); } - + # Makes an entry in the database corresponding to page creation # Note: the title object must be loaded with the new id using resetArticleID() /*static*/ function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot = "default", $ip='' ) @@ -210,14 +228,14 @@ class RecentChange 'rc_ip' => $ip, 'rc_new' => 1 # obsolete ); - + $rc->mExtra = array( 'prefixedDBkey' => $title->getPrefixedDBkey(), 'lastTimestamp' => 0 ); $rc->save(); } - + # Makes an entry in the database corresponding to a rename /*static*/ function notifyMove( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='', $overRedir = false ) { @@ -243,9 +261,10 @@ class RecentChange 'rc_moved_to_ns' => $newTitle->getNamespace(), 'rc_moved_to_title' => $newTitle->getDBkey(), 'rc_ip' => $ip, - 'rc_new' => 0 # obsolete + 'rc_new' => 0, # obsolete + 'rc_patrolled' => 1 ); - + $rc->mExtra = array( 'prefixedDBkey' => $oldTitle->getPrefixedDBkey(), 'lastTimestamp' => 0, @@ -253,7 +272,7 @@ class RecentChange ); $rc->save(); } - + /* static */ function notifyMoveToNew( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='' ) { RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip, false ); } @@ -262,7 +281,7 @@ class RecentChange RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip='', true ); } - # A log entry is different to an edit in that previous revisions are + # A log entry is different to an edit in that previous revisions are # not kept /*static*/ function notifyLog( $timestamp, &$title, &$user, $comment, $ip='' ) { @@ -288,6 +307,7 @@ class RecentChange 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', 'rc_ip' => $ip, + 'rc_patrolled' => 1, 'rc_new' => 0 # obsolete ); $rc->mExtra = array( @@ -303,7 +323,7 @@ class RecentChange $this->mAttribs = get_object_vars( $row ); $this->mExtra = array(); } - + # Makes a pseudo-RC entry from a cur row, for watchlists and things function loadFromCurRow( $row ) { diff --git a/includes/Skin.php b/includes/Skin.php index 17ddf6ee4e..fcc82a2f12 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -439,13 +439,13 @@ class Skin { $printfooter = "
      \n" . $this->printFooter() . "
      \n"; return $printfooter . $this->doAfterContent(); } - + function printSource() { global $wgTitle; $url = htmlspecialchars( $wgTitle->getFullURL() ); return wfMsg( "retrievedfrom", "$url" ); } - + function printFooter() { return "

      " . $this->printSource() . "

      \n\n

      " . $this->pageStats() . "

      \n"; @@ -2265,7 +2265,9 @@ class Skin { $this->lastdate = $date; $this->rclistOpen = true; } - $s .= '
    1. '; + + # If this edit has not yet been patrolled, make it stick out + $s .= ( $rc_patrolled ) ? '
    2. ' : '
    3. '; if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { # Diff @@ -2275,11 +2277,7 @@ class Skin { ') . . '; # "[[x]] moved to [[y]]" - if ( $rc_type == RC_MOVE ) { - $msg = '1movedto2'; - } else { - $msg = '1movedto2_redir'; - } + $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir'; $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); } else { @@ -2287,8 +2285,14 @@ class Skin { if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) { $diffLink = wfMsg( 'diff' ); } else { + if ( $rc_patrolled == 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + $rcidparam = "&rcid={$rc_id}"; + else + $rcidparam = ""; $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ), - $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid ,'' ,'' , ' tabindex="'.$rc->counter.'"'); + "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}", + '', '', ' tabindex="'.$rc->counter.'"'); } $s .= '('.$diffLink.') ('; @@ -2303,7 +2307,13 @@ class Skin { if ( $rc_type == RC_NEW ) { $s .= ''.$N.''; } # Article link - $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' ); + # If it's a new article, there is no diff link, but if it hasn't been + # patrolled yet, we need to give users a way to do so + if ( $rc_type == RC_NEW && $rc_patrolled == 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" ); + else + $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' ); if ( $watched ) { $articleLink = ''.$articleLink.''; @@ -2370,7 +2380,7 @@ class Skin { # If it's a new day, add the headline and flush the cache $date = $wgLang->date( $rc_timestamp, true); - $ret = '' ; + $ret = ''; if ( $date != $this->lastdate ) { # Process current cache $ret = $this->recentChangesBlock () ; @@ -2381,11 +2391,7 @@ class Skin { # Make article link if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { - if ( $rc_type == RC_MOVE ) { - $msg = "1movedto2"; - } else { - $msg = "1movedto2_redir"; - } + $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir"; $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); } else { @@ -2418,7 +2424,7 @@ class Skin { } # Make user link (or user contributions for unregistered users) - if ( 0 == $rc_user ) { + if ( $rc_user == 0 ) { $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ), $rc_user_text, 'target=' . $rc_user_text ); } else { @@ -2426,12 +2432,11 @@ class Skin { Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text ); } - $rc->userlink = $userLink ; - $rc->lastlink = $lastLink ; - $rc->curlink = $curLink ; + $rc->userlink = $userLink; + $rc->lastlink = $lastLink; + $rc->curlink = $curLink; $rc->difflink = $diffLink; - # Make user talk link $utns=$wgLang->getNsText(NS_USER_TALK); $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name diff --git a/includes/SpecialNewpages.php b/includes/SpecialNewpages.php index 802e9f9e29..6f5fedb34f 100644 --- a/includes/SpecialNewpages.php +++ b/includes/SpecialNewpages.php @@ -7,7 +7,7 @@ class NewPagesPage extends QueryPage { function getName() { return "Newpages"; } - + function isExpensive() { # Indexed on RC, and will *not* work with querycache yet. return false; @@ -15,6 +15,8 @@ class NewPagesPage extends QueryPage { } function getSQL() { + global $wgUser, $wgOnlySysopsCanPatrol; + $usepatrol = ( $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) ? 1 : 0; $dbr =& wfGetDB( DB_SLAVE ); extract( $dbr->tableNames( 'recentchanges', 'cur' ) ); @@ -23,11 +25,13 @@ class NewPagesPage extends QueryPage { rc_namespace AS namespace, rc_title AS title, rc_cur_id AS value, - rc_user AS user, rc_user_text AS user_text, rc_comment as comment, rc_timestamp AS timestamp, + '{$usepatrol}' as usepatrol, + rc_patrolled AS patrolled, + rc_id AS rcid, length(cur_text) as length, cur_text as text FROM $recentchanges,$cur @@ -36,7 +40,7 @@ class NewPagesPage extends QueryPage { } function formatResult( $skin, $result ) { - global $wgLang; + global $wgLang, $wgUser, $wgOnlySysopsCanPatrol; $u = $result->user; $ut = $result->user_text; @@ -51,7 +55,15 @@ class NewPagesPage extends QueryPage { } $d = $wgLang->timeanddate( $result->timestamp, true ); - $link = $skin->makeKnownLink( $result->title, "" ); + + # If it's a new article, there is no diff link, but if it hasn't been + # patrolled yet, we need to give users a way to do so + if ( $result->usepatrol && $result->patrolled == 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + $link = $skin->makeKnownLink( $result->title, '', "rcid={$result->rcid}" ); + else + $link = $skin->makeKnownLink( $result->title, '' ); + $s = "{$d} {$link} ({$length}) . . {$ul}"; if ( "" != $c && "*" != $c ) { @@ -66,7 +78,7 @@ function wfSpecialNewpages() { global $wgRequest; list( $limit, $offset ) = wfCheckLimits(); - + $npp = new NewPagesPage(); if( !$npp->doFeed( $wgRequest->getVal( 'feed' ) ) ) { diff --git a/includes/SpecialRecentchanges.php b/includes/SpecialRecentchanges.php index 2d378b25ab..414f6184b4 100644 --- a/includes/SpecialRecentchanges.php +++ b/includes/SpecialRecentchanges.php @@ -16,13 +16,14 @@ function wfSpecialRecentchanges( $par ) if ( !$defaultDays ) { $defaultDays = 3; } - + $days = $wgRequest->getInt( 'days', $defaultDays ); $hideminor = $wgRequest->getBool( 'hideminor', $wgUser->getOption( 'hideminor' ) ) ? 1 : 0; $from = $wgRequest->getText( 'from' ); $hidebots = $wgRequest->getBool( 'hidebots', true ) ? 1 : 0; $hideliu = $wgRequest->getBool( 'hideliu', false ) ? 1 : 0; - + $hidepatrolled = $wgRequest->getBool( 'hidepatrolled', false ) ? 1 : 0; + # Get query parameters from path if( $par ) { $bits = preg_split( '/\s*,\s*/', trim( $par ) ); @@ -31,11 +32,12 @@ function wfSpecialRecentchanges( $par ) if( in_array( "hideminor", $bits ) ) $hideminor = 1; if( in_array( "minor", $bits ) ) $hideminor = 0; if( in_array( "hideliu", $bits) ) $hideliu = 1; + if( in_array( "hidepatrolled", $bits) ) $hidepatrolled = 1; } - + $dbr =& wfGetDB( DB_SLAVE ); extract( $dbr->tableNames( 'recentchanges', 'watchlist' ) ); - + $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, $fname ); # 10 seconds server-side caching max $wgOut->setSquidMaxage( 10 ); @@ -45,16 +47,16 @@ function wfSpecialRecentchanges( $par ) } # The next few lines can probably be commented out now that wfMsg can get text from the DB - $rctext = $dbr->selectField( 'cur', 'cur_text', + $rctext = $dbr->selectField( 'cur', 'cur_text', array( 'cur_namespace' => NS_WIKIPEDIA, 'cur_title' => 'Recentchanges' ), $fname ); if( !$rctext ) { $rctext = wfMsg( "recentchangestext" ); } - + $wgOut->addWikiText( $rctext ); - + list( $limit, $offset ) = wfCheckLimits( 100, "rclimit" ); $now = wfTimestampNow(); $cutoff_unixtime = time() - ( $days * 86400 ); @@ -68,31 +70,24 @@ function wfSpecialRecentchanges( $par ) $sk = $wgUser->getSkin(); $showhide = array( wfMsg( "show" ), wfMsg( "hide" )); - - if ( $hideminor ) { - $hidem = "AND rc_minor=0"; - } else { - $hidem = ""; - } - - if( $hidebots ) { - $hidem .= " AND rc_bot=0"; - } - - if ( $hideliu ) { - $hidem .= " AND rc_user=0"; - } - $hideliu = ($hideliu ? 1 : 0); - #$hideparams = "hideminor={$hideminor}&hideliu={$hideliu}&hidebots={$hidebots}"; - $urlparams = array( "hideminor" => $hideminor, "hideliu" => $hideliu, "hidebots" => $hidebots ); + + $hidem = ( $hideminor ) ? "AND rc_minor=0" : ""; + $hidem .= ( $hidebots ) ? " AND rc_bot=0" : ""; + $hidem .= ( $hideliu ) ? " AND rc_user=0" : ""; + $hidem .= ( $hidepatrolled )? " AND rc_patrolled=0" : ""; + + $urlparams = array( "hideminor" => $hideminor, "hideliu" => $hideliu, + "hidebots" => $hidebots, "hidepatrolled" => $hidepatrolled ); $hideparams = wfArrayToCGI( $urlparams ); - + $minorLink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), $showhide[1-$hideminor], wfArrayToCGI( array( "hideminor" => 1-$hideminor ), $urlparams ) ); $botLink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), $showhide[1-$hidebots], wfArrayToCGI( array( "hidebots" => 1-$hidebots ), $urlparams ) ); $liuLink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), $showhide[1-$hideliu], wfArrayToCGI( array( "hideliu" => 1-$hideliu ), $urlparams ) ); + $patrLink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), + $showhide[1-$hidepatrolled], wfArrayToCGI( array( "hidepatrolled" => 1-$hidepatrolled ), $urlparams ) ); $uid = $wgUser->getID(); $sql2 = "SELECT $recentchanges.*" . ($uid ? ",wl_user" : "") . " FROM $recentchanges " . @@ -102,11 +97,11 @@ function wfSpecialRecentchanges( $par ) $res = $dbr->query( $sql2, DB_SLAVE, $fname ); $rows = array(); - while( $row = $dbr->fetchObject( $res ) ){ - $rows[] = $row; + while( $row = $dbr->fetchObject( $res ) ){ + $rows[] = $row; } $dbr->freeResult( $res ); - + if(isset($from)) { $note = wfMsg( "rcnotefrom", $wgLang->formatNum( $limit ), $wgLang->timeanddate( $from, true ) ); @@ -115,7 +110,7 @@ function wfSpecialRecentchanges( $par ) } $wgOut->addHTML( "\n
      \n{$note}\n
      " ); - $note = rcDayLimitLinks( $days, $limit, "Recentchanges", $hideparams, false, $minorLink, $botLink, $liuLink ); + $note = rcDayLimitLinks( $days, $limit, "Recentchanges", $hideparams, false, $minorLink, $botLink, $liuLink, $patrLink ); $note .= "
      \n" . wfMsg( "rclistfrom", $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), @@ -149,10 +144,11 @@ function wfSpecialRecentchanges( $par ) $counter = 1; foreach( $rows as $obj ){ if( $limit == 0) { - break; + break; } - - if ( ! ( $hideminor && $obj->rc_minor ) ) { + + if ( ! ( $hideminor && $obj->rc_minor ) && + ! ( $hidepatrolled && $obj->rc_patrolled ) ) { $rc = RecentChange::newFromRow( $obj ); $rc->counter = $counter++; $s .= $sk->recentChangesLine( $rc, !empty( $obj->wl_user ) ); @@ -184,8 +180,8 @@ function rcDaysLink( $lim, $d, $page="Recentchanges", $more="" ) return $s; } -function rcDayLimitLinks( $days, $limit, $page="Recentchanges", $more="", $doall = false, $minorLink = "", - $botLink = "", $liuLink = "" ) +function rcDayLimitLinks( $days, $limit, $page="Recentchanges", $more="", $doall = false, $minorLink = "", + $botLink = "", $liuLink = "", $patrLink = "" ) { if ($more != "") $more .= "&"; $cl = rcCountLink( 50, $days, $page, $more ) . " | " . @@ -199,7 +195,7 @@ function rcDayLimitLinks( $days, $limit, $page="Recentchanges", $more="", $doall rcDaysLink( $limit, 14, $page, $more ) . " | " . rcDaysLink( $limit, 30, $page, $more ) . ( $doall ? ( " | " . rcDaysLink( $limit, 0, $page, $more ) ) : "" ); - $shm = wfMsg( "showhideminor", $minorLink, $botLink, $liuLink ); + $shm = wfMsg( "showhideminor", $minorLink, $botLink, $liuLink, $patrLink ); $note = wfMsg( "rclinks", $cl, $dl, $shm ); return $note; } diff --git a/languages/Language.php b/languages/Language.php index e72c7969a0..8ff162bb89 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -1428,12 +1428,19 @@ You might want to check the following regular expression for patterns that are c "numtalkauthors" => "Number of distinct authors (discussion page): $1", # Math options - 'mw_math_png' => 'Always render PNG', - 'mw_math_simple' => 'HTML if very simple or else PNG', - 'mw_math_html' => 'HTML if possible or else PNG', - 'mw_math_source' => 'Leave it as TeX (for text browsers)', - 'mw_math_modern' => 'Recommended for modern browsers', - 'mw_math_mathml' => 'MathML if possible (experimental)', +'mw_math_png' => 'Always render PNG', +'mw_math_simple' => 'HTML if very simple or else PNG', +'mw_math_html' => 'HTML if possible or else PNG', +'mw_math_source' => 'Leave it as TeX (for text browsers)', +'mw_math_modern' => 'Recommended for modern browsers', +'mw_math_mathml' => 'MathML if possible (experimental)', + +# Patrolling +'markaspatrolleddiff' => "Mark as patrolled", +'markaspatrolledlink' => "", +'markaspatrolledtext' => "Mark this article as patrolled", +'markedaspatrolled' => "Marked as patrolled", +'markedaspatrolledtext' => "The selected revision has been marked as patrolled.", # Monobook.js: tooltips and access keys for monobook 'Monobook.js' => '/* tooltips and access keys */ @@ -1870,7 +1877,7 @@ class Language { } return $s; } - + # Crop a string from the beginning or end to a certain number of bytes. # (Bytes are used because our storage has limited byte lengths for some # columns in the database.) Multibyte charsets will need to make sure that diff --git a/maintenance/archives/patch-rc-patrol.sql b/maintenance/archives/patch-rc-patrol.sql new file mode 100755 index 0000000000..51fd3c668e --- /dev/null +++ b/maintenance/archives/patch-rc-patrol.sql @@ -0,0 +1,9 @@ +-- +-- patch-rc-patrol.sql +-- Adds a row to recentchanges for the patrolling feature +-- 2004-08-09 +-- + +ALTER TABLE recentchanges + ADD COLUMN rc_patrolled tinyint(3) unsigned NOT NULL default '0'; + diff --git a/maintenance/tables.sql b/maintenance/tables.sql index dc8194f273..b726f75794 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -12,11 +12,11 @@ CREATE TABLE user ( user_password tinyblob NOT NULL default '', user_newpassword tinyblob NOT NULL default '', user_email tinytext NOT NULL default '', - user_options blob NOT NULL default '', + user_options blob NOT NULL default '', user_touched char(14) binary NOT NULL default '', UNIQUE KEY user_id (user_id) ) PACK_KEYS=1; - + CREATE TABLE user_newtalk ( user_id int(5) NOT NULL default '0', user_ip varchar(40) NOT NULL default '' @@ -192,6 +192,7 @@ CREATE TABLE recentchanges ( rc_type tinyint(3) unsigned NOT NULL default '0', rc_moved_to_ns tinyint(3) unsigned NOT NULL default '0', rc_moved_to_title varchar(255) binary NOT NULL default '', + rc_patrolled tinyint(3) unsigned NOT NULL default '0', rc_ip char(15) NOT NULL default '', PRIMARY KEY rc_id (rc_id) ) PACK_KEYS=1; diff --git a/stylesheets/monobook/main.css b/stylesheets/monobook/main.css index b6d3f82297..603d2b67bf 100644 --- a/stylesheets/monobook/main.css +++ b/stylesheets/monobook/main.css @@ -906,3 +906,11 @@ fieldset.operaprefsection { margin-left: 15em } .printfooter { display: none; } + +ul.special li.not_patrolled, ol.special li.not_patrolled { + background-color: #ffa; +} +div.patrollink { + font-size: 75%; + text-align: right; +} -- 2.20.1