Merge "Add ability to filter based on rc_title in API"
[lhc/web/wiklou.git] / includes / import / WikiRevision.php
index df71524..55a7b2d 100644 (file)
  * @file
  * @ingroup SpecialPage
  */
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Represents a revision, log entry or upload during the import process.
  * This class sticks closely to the structure of the XML dump.
  *
+ * @since 1.2
+ *
  * @ingroup SpecialPage
  */
-class WikiRevision {
+class WikiRevision implements ImportableUploadRevision, ImportableOldRevision {
 
        /**
         * @since 1.17
@@ -39,79 +43,143 @@ class WikiRevision {
         */
        public $importer = null;
 
-       /** @var Title */
+       /**
+        * @since 1.2
+        * @var Title
+        */
        public $title = null;
 
-       /** @var int */
+       /**
+        * @since 1.6.4
+        * @var int
+        */
        public $id = 0;
 
-       /** @var string */
+       /**
+        * @since 1.2
+        * @var string
+        */
        public $timestamp = "20010115000000";
 
        /**
+        * @since 1.2
         * @var int
         * @deprecated in 1.29. Unused.
         * @note Introduced in 436a028086fb3f01c4605c5ad2964d56f9306aca, unused there, unused now.
         */
        public $user = 0;
 
-       /** @var string */
+       /**
+        * @since 1.2
+        * @var string
+        */
        public $user_text = "";
 
-       /** @var User */
+       /**
+        * @since 1.27
+        * @var User
+        */
        public $userObj = null;
 
-       /** @var string */
+       /**
+        * @since 1.21
+        * @var string
+        */
        public $model = null;
 
-       /** @var string */
+       /**
+        * @since 1.21
+        * @var string
+        */
        public $format = null;
 
-       /** @var string */
+       /**
+        * @since 1.2
+        * @var string
+        */
        public $text = "";
 
-       /** @var int */
+       /**
+        * @since 1.12.2
+        * @var int
+        */
        protected $size;
 
-       /** @var Content */
+       /**
+        * @since 1.21
+        * @var Content
+        */
        public $content = null;
 
-       /** @var ContentHandler */
+       /**
+        * @since 1.24
+        * @var ContentHandler
+        */
        protected $contentHandler = null;
 
-       /** @var string */
+       /**
+        * @since 1.2.6
+        * @var string
+        */
        public $comment = "";
 
-       /** @var bool */
+       /**
+        * @since 1.5.7
+        * @var bool
+        */
        public $minor = false;
 
-       /** @var string */
+       /**
+        * @since 1.12.2
+        * @var string
+        */
        public $type = "";
 
-       /** @var string */
+       /**
+        * @since 1.12.2
+        * @var string
+        */
        public $action = "";
 
-       /** @var string */
+       /**
+        * @since 1.12.2
+        * @var string
+        */
        public $params = "";
 
-       /** @var string */
+       /**
+        * @since 1.17
+        * @var string
+        */
        public $fileSrc = '';
 
-       /** @var bool|string */
+       /**
+        * @since 1.17
+        * @var bool|string
+        */
        public $sha1base36 = false;
 
        /**
-       /** @var string */
+        * @since 1.17
+        * @var string
+        */
        public $archiveName = '';
 
+       /**
+        * @since 1.12.2
+        */
        protected $filename;
 
-       /** @var mixed */
-       protected $src;
+       /**
+        * @since 1.12.2
+        * @var string|null
+        */
+       protected $src = null;
 
        /**
         * @since 1.18
         * @var bool
+        * @todo Unused?
         */
        public $isTemp = false;
 
@@ -134,6 +202,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.7 taking a Title object (string before)
         * @param Title $title
         * @throws MWException
         */
@@ -149,6 +218,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.6.4
         * @param int $id
         */
        public function setID( $id ) {
@@ -156,6 +226,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @param string $ts
         */
        public function setTimestamp( $ts ) {
@@ -164,6 +235,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @param string $user
         */
        public function setUsername( $user ) {
@@ -171,6 +243,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.27
         * @param User $user
         */
        public function setUserObj( $user ) {
@@ -178,6 +251,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @param string $ip
         */
        public function setUserIP( $ip ) {
@@ -185,6 +259,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.21
         * @param string $model
         */
        public function setModel( $model ) {
@@ -192,6 +267,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.21
         * @param string $format
         */
        public function setFormat( $format ) {
@@ -199,6 +275,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @param string $text
         */
        public function setText( $text ) {
@@ -206,6 +283,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2.6
         * @param string $text
         */
        public function setComment( $text ) {
@@ -213,6 +291,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.5.7
         * @param bool $minor
         */
        public function setMinor( $minor ) {
@@ -220,13 +299,15 @@ class WikiRevision {
        }
 
        /**
-        * @param mixed $src
+        * @since 1.12.2
+        * @param string|null $src
         */
        public function setSrc( $src ) {
                $this->src = $src;
        }
 
        /**
+        * @since 1.17
         * @param string $src
         * @param bool $isTemp
         */
@@ -237,6 +318,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.17
         * @param string $sha1base36
         */
        public function setSha1Base36( $sha1base36 ) {
@@ -244,6 +326,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @param string $filename
         */
        public function setFilename( $filename ) {
@@ -251,6 +334,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.17
         * @param string $archiveName
         */
        public function setArchiveName( $archiveName ) {
@@ -258,6 +342,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @param int $size
         */
        public function setSize( $size ) {
@@ -265,6 +350,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @param string $type
         */
        public function setType( $type ) {
@@ -272,6 +358,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @param string $action
         */
        public function setAction( $action ) {
@@ -279,6 +366,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @param array $params
         */
        public function setParams( $params ) {
@@ -286,6 +374,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.18
         * @param bool $noupdates
         */
        public function setNoUpdates( $noupdates ) {
@@ -293,6 +382,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @return Title
         */
        public function getTitle() {
@@ -300,6 +390,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.6.4
         * @return int
         */
        public function getID() {
@@ -307,6 +398,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @return string
         */
        public function getTimestamp() {
@@ -314,6 +406,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @return string
         */
        public function getUser() {
@@ -321,6 +414,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.27
         * @return User
         */
        public function getUserObj() {
@@ -328,6 +422,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2
         * @return string
         */
        public function getText() {
@@ -335,6 +430,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.24
         * @return ContentHandler
         */
        public function getContentHandler() {
@@ -346,6 +442,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.21
         * @return Content
         */
        public function getContent() {
@@ -358,6 +455,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.21
         * @return string
         */
        public function getModel() {
@@ -369,6 +467,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.21
         * @return string
         */
        public function getFormat() {
@@ -380,6 +479,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.2.6
         * @return string
         */
        public function getComment() {
@@ -387,6 +487,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.5.7
         * @return bool
         */
        public function getMinor() {
@@ -394,13 +495,15 @@ class WikiRevision {
        }
 
        /**
-        * @return mixed
+        * @since 1.12.2
+        * @return string|null
         */
        public function getSrc() {
                return $this->src;
        }
 
        /**
+        * @since 1.17
         * @return bool|string
         */
        public function getSha1() {
@@ -411,6 +514,18 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.31
+        * @return bool|string
+        */
+       public function getSha1Base36() {
+               if ( $this->sha1base36 ) {
+                       return $this->sha1base36;
+               }
+               return false;
+       }
+
+       /**
+        * @since 1.17
         * @return string
         */
        public function getFileSrc() {
@@ -418,6 +533,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.17
         * @return bool
         */
        public function isTempSrc() {
@@ -425,6 +541,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @return mixed
         */
        public function getFilename() {
@@ -432,6 +549,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.17
         * @return string
         */
        public function getArchiveName() {
@@ -439,6 +557,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @return mixed
         */
        public function getSize() {
@@ -446,6 +565,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @return string
         */
        public function getType() {
@@ -453,6 +573,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @return string
         */
        public function getAction() {
@@ -460,6 +581,7 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.12.2
         * @return string
         */
        public function getParams() {
@@ -467,118 +589,27 @@ class WikiRevision {
        }
 
        /**
+        * @since 1.4.1
+        * @deprecated in 1.31. Use OldRevisionImporter::import
         * @return bool
         */
        public function importOldRevision() {
-               $dbw = wfGetDB( DB_MASTER );
-
-               # Sneak a single revision into place
-               $user = $this->getUserObj() ?: User::newFromName( $this->getUser() );
-               if ( $user ) {
-                       $userId = intval( $user->getId() );
-                       $userText = $user->getName();
+               if ( $this->mNoUpdates ) {
+                       $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporterNoUpdates();
                } else {
-                       $userId = 0;
-                       $userText = $this->getUser();
-                       $user = new User;
-               }
-
-               // avoid memory leak...?
-               Title::clearCaches();
-
-               $page = WikiPage::factory( $this->title );
-               $page->loadPageData( 'fromdbmaster' );
-               if ( !$page->exists() ) {
-                       // must create the page...
-                       $pageId = $page->insertOn( $dbw );
-                       $created = true;
-                       $oldcountable = null;
-               } else {
-                       $pageId = $page->getId();
-                       $created = false;
-
-                       $prior = $dbw->selectField( 'revision', '1',
-                               [ 'rev_page' => $pageId,
-                                       'rev_timestamp' => $dbw->timestamp( $this->timestamp ),
-                                       'rev_user_text' => $userText,
-                                       'rev_comment' => $this->getComment() ],
-                               __METHOD__
-                       );
-                       if ( $prior ) {
-                               // @todo FIXME: This could fail slightly for multiple matches :P
-                               wfDebug( __METHOD__ . ": skipping existing revision for [[" .
-                                       $this->title->getPrefixedText() . "]], timestamp " . $this->timestamp . "\n" );
-                               return false;
-                       }
-               }
-
-               if ( !$pageId ) {
-                       // This seems to happen if two clients simultaneously try to import the
-                       // same page
-                       wfDebug( __METHOD__ . ': got invalid $pageId when importing revision of [[' .
-                               $this->title->getPrefixedText() . ']], timestamp ' . $this->timestamp . "\n" );
-                       return false;
-               }
-
-               // Select previous version to make size diffs correct
-               // @todo This assumes that multiple revisions of the same page are imported
-               // in order from oldest to newest.
-               $prevId = $dbw->selectField( 'revision', 'rev_id',
-                       [
-                               'rev_page' => $pageId,
-                               'rev_timestamp <= ' . $dbw->addQuotes( $dbw->timestamp( $this->timestamp ) ),
-                       ],
-                       __METHOD__,
-                       [ 'ORDER BY' => [
-                                       'rev_timestamp DESC',
-                                       'rev_id DESC', // timestamp is not unique per page
-                               ]
-                       ]
-               );
-
-               # @todo FIXME: Use original rev_id optionally (better for backups)
-               # Insert the row
-               $revision = new Revision( [
-                       'title' => $this->title,
-                       'page' => $pageId,
-                       'content_model' => $this->getModel(),
-                       'content_format' => $this->getFormat(),
-                       // XXX: just set 'content' => $this->getContent()?
-                       'text' => $this->getContent()->serialize( $this->getFormat() ),
-                       'comment' => $this->getComment(),
-                       'user' => $userId,
-                       'user_text' => $userText,
-                       'timestamp' => $this->timestamp,
-                       'minor_edit' => $this->minor,
-                       'parent_id' => $prevId,
-                       ] );
-               $revision->insertOn( $dbw );
-               $changed = $page->updateIfNewerOn( $dbw, $revision );
-
-               if ( $changed !== false && !$this->mNoUpdates ) {
-                       wfDebug( __METHOD__ . ": running updates\n" );
-                       // countable/oldcountable stuff is handled in WikiImporter::finishImportPage
-                       $page->doEditUpdates(
-                               $revision,
-                               $user,
-                               [ 'created' => $created, 'oldcountable' => 'no-change' ]
-                       );
+                       $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporter();
                }
-
-               return true;
+               return $importer->import( $this );
        }
 
+       /**
+        * @since 1.12.2
+        * @return bool
+        */
        public function importLogItem() {
                $dbw = wfGetDB( DB_MASTER );
 
-               $user = $this->getUserObj() ?: User::newFromName( $this->getUser() );
-               if ( $user ) {
-                       $userId = intval( $user->getId() );
-                       $userText = $user->getName();
-               } else {
-                       $userId = 0;
-                       $userText = $this->getUser();
-               }
+               $user = $this->getUserObj() ?: User::newFromName( $this->getUser(), false );
 
                # @todo FIXME: This will not record autoblocks
                if ( !$this->getTitle() ) {
@@ -594,8 +625,6 @@ class WikiRevision {
                                'log_timestamp' => $dbw->timestamp( $this->timestamp ),
                                'log_namespace' => $this->getTitle()->getNamespace(),
                                'log_title' => $this->getTitle()->getDBkey(),
-                               'log_comment' => $this->getComment(),
-                               # 'log_user_text' => $this->user_text,
                                'log_params' => $this->params ],
                        __METHOD__
                );
@@ -606,124 +635,42 @@ class WikiRevision {
                                . $this->timestamp . "\n" );
                        return false;
                }
-               $log_id = $dbw->nextSequenceValue( 'logging_log_id_seq' );
                $data = [
-                       'log_id' => $log_id,
                        'log_type' => $this->type,
                        'log_action' => $this->action,
                        'log_timestamp' => $dbw->timestamp( $this->timestamp ),
-                       'log_user' => $userId,
-                       'log_user_text' => $userText,
                        'log_namespace' => $this->getTitle()->getNamespace(),
                        'log_title' => $this->getTitle()->getDBkey(),
-                       'log_comment' => $this->getComment(),
                        'log_params' => $this->params
-               ];
+               ] + CommentStore::getStore()->insert( $dbw, 'log_comment', $this->getComment() )
+                       + ActorMigration::newMigration()->getInsertValues( $dbw, 'log_user', $user );
                $dbw->insert( 'logging', $data, __METHOD__ );
 
                return true;
        }
 
        /**
+        * @since 1.12.2
+        * @deprecated in 1.31. Use UploadImporter::import
         * @return bool
         */
        public function importUpload() {
-               # Construct a file
-               $archiveName = $this->getArchiveName();
-               if ( $archiveName ) {
-                       wfDebug( __METHOD__ . "Importing archived file as $archiveName\n" );
-                       $file = OldLocalFile::newFromArchiveName( $this->getTitle(),
-                               RepoGroup::singleton()->getLocalRepo(), $archiveName );
-               } else {
-                       $file = wfLocalFile( $this->getTitle() );
-                       $file->load( File::READ_LATEST );
-                       wfDebug( __METHOD__ . 'Importing new file as ' . $file->getName() . "\n" );
-                       if ( $file->exists() && $file->getTimestamp() > $this->getTimestamp() ) {
-                               $archiveName = $file->getTimestamp() . '!' . $file->getName();
-                               $file = OldLocalFile::newFromArchiveName( $this->getTitle(),
-                                       RepoGroup::singleton()->getLocalRepo(), $archiveName );
-                               wfDebug( __METHOD__ . "File already exists; importing as $archiveName\n" );
-                       }
-               }
-               if ( !$file ) {
-                       wfDebug( __METHOD__ . ': Bad file for ' . $this->getTitle() . "\n" );
-                       return false;
-               }
-
-               # Get the file source or download if necessary
-               $source = $this->getFileSrc();
-               $autoDeleteSource = $this->isTempSrc();
-               if ( !strlen( $source ) ) {
-                       $source = $this->downloadSource();
-                       $autoDeleteSource = true;
-               }
-               if ( !strlen( $source ) ) {
-                       wfDebug( __METHOD__ . ": Could not fetch remote file.\n" );
-                       return false;
-               }
-
-               $tmpFile = new TempFSFile( $source );
-               if ( $autoDeleteSource ) {
-                       $tmpFile->autocollect();
-               }
-
-               $sha1File = ltrim( sha1_file( $source ), '0' );
-               $sha1 = $this->getSha1();
-               if ( $sha1 && ( $sha1 !== $sha1File ) ) {
-                       wfDebug( __METHOD__ . ": Corrupt file $source.\n" );
-                       return false;
-               }
-
-               $user = $this->getUserObj() ?: User::newFromName( $this->getUser() );
-
-               # Do the actual upload
-               if ( $archiveName ) {
-                       $status = $file->uploadOld( $source, $archiveName,
-                               $this->getTimestamp(), $this->getComment(), $user );
-               } else {
-                       $flags = 0;
-                       $status = $file->upload( $source, $this->getComment(), $this->getComment(),
-                               $flags, false, $this->getTimestamp(), $user );
-               }
-
-               if ( $status->isGood() ) {
-                       wfDebug( __METHOD__ . ": Successful\n" );
-                       return true;
-               } else {
-                       wfDebug( __METHOD__ . ': failed: ' . $status->getHTML() . "\n" );
-                       return false;
-               }
+               $importer = MediaWikiServices::getInstance()->getWikiRevisionUploadImporter();
+               $statusValue = $importer->import( $this );
+               return $statusValue->isGood();
        }
 
        /**
+        * @since 1.12.2
+        * @deprecated in 1.31. Use UploadImporter::downloadSource
         * @return bool|string
         */
        public function downloadSource() {
-               if ( !$this->config->get( 'EnableUploads' ) ) {
-                       return false;
-               }
-
-               $tempo = tempnam( wfTempDir(), 'download' );
-               $f = fopen( $tempo, 'wb' );
-               if ( !$f ) {
-                       wfDebug( "IMPORT: couldn't write to temp file $tempo\n" );
-                       return false;
-               }
-
-               // @todo FIXME!
-               $src = $this->getSrc();
-               $data = Http::get( $src, [], __METHOD__ );
-               if ( !$data ) {
-                       wfDebug( "IMPORT: couldn't fetch source $src\n" );
-                       fclose( $f );
-                       unlink( $tempo );
-                       return false;
-               }
-
-               fwrite( $f, $data );
-               fclose( $f );
-
-               return $tempo;
+               $importer = new ImportableUploadRevisionImporter(
+                       $this->config->get( 'EnableUploads' ),
+                       LoggerFactory::getInstance( 'UploadRevisionImporter' )
+               );
+               return $importer->downloadSource( $this );
        }
 
 }