From 5349ea2dd8d7702b264302bd915fac5e06c5c09b Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Sat, 28 Feb 2009 13:25:21 +0000 Subject: [PATCH] * API: (bug 13209) Add rvdiffto parameter to prop=revisions * Add $wgAPIMaxUncachedDiffs (default 1) which controls how many non-cached diffs will be served per request * Tweak DifferenceEngine.php a bit to make cache status accessible, and remove a useless 'parseinline' which broke diff generation in the API --- RELEASE-NOTES | 1 + includes/DefaultSettings.php | 6 ++++ includes/api/ApiBase.php | 2 +- includes/api/ApiQueryRevisions.php | 47 ++++++++++++++++++++++++++---- includes/diff/DifferenceEngine.php | 32 +++++++++++++++----- 5 files changed, 75 insertions(+), 13 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 597324d9af..12801ce7f3 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -265,6 +265,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN aliases already listed in siprop=namespaces * (bug 17529) rvend ignored when rvstartid is specified * (bug 17626) Added uiprop=email to list=userinfo +* (bug 13209) Added rvdiffto parameter to prop=revisions === Languages updated in 1.15 === diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 1a5e95eed6..26836b7c86 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -3561,6 +3561,12 @@ $wgAPIMaxDBRows = 5000; */ $wgAPIMaxResultSize = 8388608; +/** + * The maximum number of uncached diffs that can be retrieved in one API + * request. Set this to 0 to disable API diffs altogether + */ +$wgAPIMaxUncachedDiffs = 1; + /** * Parser test suite files to be run by parserTests.php when no specific * filename is passed to it. diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index ff21a8e05d..ad2b4e497e 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -988,4 +988,4 @@ abstract class ApiBase { public static function getBaseVersion() { return __CLASS__ . ': $Id$'; } -} \ No newline at end of file +} diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 9984986fd1..801f7049e3 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -100,6 +100,26 @@ class ApiQueryRevisions extends ApiQueryBase { if ($pageCount > 1 && $enumRevMode) $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start and end parameters may only be used on a single page.', 'multpages'); + if (!is_null($params['diffto'])) { + if ($params['diffto'] == 'cur') + $params['diffto'] = 0; + if ((!ctype_digit($params['diffto']) || $params['diffto'] < 0) + && $params['diffto'] != 'prev' && $params['diffto'] != 'next') + $this->dieUsage('rvdiffto must be set to a non-negative number, "prev", "next" or "cur"', 'diffto'); + // Check whether the revision exists and is readable, + // DifferenceEngine returns a rather ambiguous empty + // string if that's not the case + if ($params['diffto'] != 0) { + $difftoRev = Revision::newFromID($params['diffto']); + if (!$difftoRev) + $this->dieUsageMsg(array('nosuchrevid', $params['diffto'])); + if (!$difftoRev->userCan(Revision::DELETED_TEXT)) { + $this->setWarning("Couldn't diff to r{$difftoRev->getID()}: content is hidden"); + $params['diffto'] = null; + } + } + } + $this->addTables('revision'); $this->addFields(Revision::selectFields()); $this->addTables('page'); @@ -116,6 +136,7 @@ class ApiQueryRevisions extends ApiQueryBase { $this->fld_size = isset ($prop['size']); $this->fld_user = isset ($prop['user']); $this->token = $params['token']; + $this->diffto = $params['diffto']; if ( !is_null($this->token) || $pageCount > 0) { $this->addFields( Revision::selectPageFields() ); @@ -288,7 +309,7 @@ class ApiQueryRevisions extends ApiQueryBase { } private function extractRowInfo( $revision ) { - + $title = $revision->getTitle(); $vals = array (); if ($this->fld_ids) { @@ -325,10 +346,7 @@ class ApiQueryRevisions extends ApiQueryBase { if (strval($comment) !== '') $vals['comment'] = $comment; } - } - - if(!is_null($this->token) || ($this->fld_content && $this->expandTemplates)) - $title = $revision->getTitle(); + } if(!is_null($this->token)) { @@ -372,6 +390,22 @@ class ApiQueryRevisions extends ApiQueryBase { } else if ($this->fld_content) { $vals['texthidden'] = ''; } + + if (!is_null($this->diffto)) { + global $wgAPIMaxUncachedDiffs; + static $n = 0; // Numer of uncached diffs we've had + if($n< $wgAPIMaxUncachedDiffs) { + $engine = new DifferenceEngine($title, $revision->getID(), $this->diffto); + $difftext = $engine->getDiffBody(); + $vals['diff']['from'] = $engine->getOldid(); + $vals['diff']['to'] = $engine->getNewid(); + ApiResult::setContent($vals['diff'], $difftext); + if(!$engine->wasCacheHit()) + $n++; + } else { + $vals['diff']['notcached'] = ''; + } + } return $vals; } @@ -429,6 +463,7 @@ class ApiQueryRevisions extends ApiQueryBase { ApiBase :: PARAM_ISMULTI => true ), 'continue' => null, + 'diffto' => null, ); } @@ -448,6 +483,8 @@ class ApiQueryRevisions extends ApiQueryBase { 'section' => 'only retrieve the content of this section', 'token' => 'Which tokens to obtain for each revision', 'continue' => 'When more results are available, use this to continue', + 'diffto' => array('Revision ID to diff each revision to.', + 'Use "prev", "next" and "cur" for the previous, next and current revision respectively.'), ); } diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index 975ecea54e..da1215e611 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -27,6 +27,7 @@ class DifferenceEngine { var $mOldRev, $mNewRev; var $mRevisionsLoaded = false; // Have the revisions been loaded var $mTextLoaded = 0; // How many text blobs have been loaded, 0, 1 or 2? + var $mCacheHit = false; // Was the diff fetched from cache? var $htmldiff; protected $unhide = false; @@ -52,9 +53,8 @@ class DifferenceEngine { $this->mNewid = intval($old); $this->mOldid = $this->mTitle->getPreviousRevisionID( $this->mNewid ); } elseif ( 'next' === $new ) { - # Show diff between revision $old and the previous one. - # Get previous one from DB. - # + # Show diff between revision $old and the next one. + # Get next one from DB. $this->mOldid = intval($old); $this->mNewid = $this->mTitle->getNextRevisionID( $this->mOldid ); if ( false === $this->mNewid ) { @@ -76,6 +76,18 @@ class DifferenceEngine { function getTitle() { return $this->mTitle; } + + function wasCacheHit() { + return $this->mCacheHit; + } + + function getOldid() { + return $this->mOldid; + } + + function getNewid() { + return $this->mNewid; + } function showDiffPage( $diffOnly = false ) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol, $wgEnableHtmlDiff; @@ -537,11 +549,16 @@ CONTROL; function getDiffBody() { global $wgMemc; wfProfileIn( __METHOD__ ); + $this->mCacheHit = true; // Check if the diff should be hidden from this user + if ( !$this->loadRevisionData() ) + return ''; if ( $this->mOldRev && !$this->mOldRev->userCan(Revision::DELETED_TEXT) ) { return ''; } else if ( $this->mNewRev && !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) { return ''; + } else if ( $this->mOldRev && $this->mNewRev && $this->mOldRev->getID() == $this->mNewRev->getID() ) { + return ''; } // Cacheable? $key = false; @@ -559,6 +576,7 @@ CONTROL; } } // don't try to load but save the result } + $this->mCacheHit = false; // Loadtext is permission safe, this just clears out the diff if ( !$this->loadText() ) { @@ -691,7 +709,7 @@ CONTROL; function localiseLineNumbersCb( $matches ) { global $wgLang; - return wfMsgExt( 'lineno', array( 'parseinline' ), $wgLang->formatNum( $matches[1] ) ); + return wfMsgExt( 'lineno', array (), $wgLang->formatNum( $matches[1] ) ); } @@ -773,10 +791,10 @@ CONTROL; // Load the new revision object $this->mNewRev = $this->mNewid - ? Revision::newFromId( $this->mNewid ) - : Revision::newFromTitle( $this->mTitle ); + ? Revision::newFromId( $this->mNewid ) + : Revision::newFromTitle( $this->mTitle ); if( !$this->mNewRev instanceof Revision ) - return false; + return false; // Update the new revision ID in case it was 0 (makes life easier doing UI stuff) $this->mNewid = $this->mNewRev->getId(); -- 2.20.1