* API: (bug 13209) Add rvdiffto parameter to prop=revisions
authorRoan Kattouw <catrope@users.mediawiki.org>
Sat, 28 Feb 2009 13:25:21 +0000 (13:25 +0000)
committerRoan Kattouw <catrope@users.mediawiki.org>
Sat, 28 Feb 2009 13:25:21 +0000 (13:25 +0000)
* 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
includes/DefaultSettings.php
includes/api/ApiBase.php
includes/api/ApiQueryRevisions.php
includes/diff/DifferenceEngine.php

index 597324d..12801ce 100644 (file)
@@ -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 ===
 
index 1a5e95e..26836b7 100644 (file)
@@ -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.
index ff21a8e..ad2b4e4 100644 (file)
@@ -988,4 +988,4 @@ abstract class ApiBase {
        public static function getBaseVersion() {
                return __CLASS__ . ': $Id$';
        }
-}
\ No newline at end of file
+}
index 9984986..801f704 100644 (file)
@@ -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.'),
                );
        }
 
index 975ecea..da1215e 100644 (file)
@@ -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();