From 25fbfd9b9c36182bf9202a738b942c561429e8e7 Mon Sep 17 00:00:00 2001 From: addshore Date: Tue, 4 Jul 2017 22:07:04 +0100 Subject: [PATCH] Factor UploadRevisionImporter & ImportableUploadRevision out of WikiRevision This is to be used within the FileImporter extension to allow adding custom loggers to this import process. Change-Id: I4a6c573fc0a69b06d696cd2afca9226fb492a9bc --- autoload.php | 3 + includes/MediaWikiServices.php | 8 + includes/ServiceWiring.php | 7 + includes/import/ImportableUploadRevision.php | 68 ++++++++ .../ImportableUploadRevisionImporter.php | 154 ++++++++++++++++++ includes/import/UploadRevisionImporter.php | 18 ++ includes/import/WikiRevision.php | 112 ++----------- 7 files changed, 275 insertions(+), 95 deletions(-) create mode 100644 includes/import/ImportableUploadRevision.php create mode 100644 includes/import/ImportableUploadRevisionImporter.php create mode 100644 includes/import/UploadRevisionImporter.php diff --git a/autoload.php b/autoload.php index 9042f7b808..88a6425dcb 100644 --- a/autoload.php +++ b/autoload.php @@ -647,6 +647,8 @@ $wgAutoloadLocalClasses = [ 'ImportStringSource' => __DIR__ . '/includes/import/ImportStringSource.php', 'ImportTextFiles' => __DIR__ . '/maintenance/importTextFiles.php', 'ImportTitleFactory' => __DIR__ . '/includes/title/ImportTitleFactory.php', + 'ImportableUploadRevision' => __DIR__ . '/includes/import/ImportableUploadRevision.php', + 'ImportableUploadRevisionImporter' => __DIR__ . '/includes/import/ImportableUploadRevisionImporter.php', 'IncludableSpecialPage' => __DIR__ . '/includes/specialpage/IncludableSpecialPage.php', 'IndexPager' => __DIR__ . '/includes/pager/IndexPager.php', 'InfoAction' => __DIR__ . '/includes/actions/InfoAction.php', @@ -1570,6 +1572,7 @@ $wgAutoloadLocalClasses = [ 'UploadFromStash' => __DIR__ . '/includes/upload/UploadFromStash.php', 'UploadFromUrl' => __DIR__ . '/includes/upload/UploadFromUrl.php', 'UploadLogFormatter' => __DIR__ . '/includes/logging/UploadLogFormatter.php', + 'UploadRevisionImporter' => __DIR__ . '/includes/import/UploadRevisionImporter.php', 'UploadSourceAdapter' => __DIR__ . '/includes/import/UploadSourceAdapter.php', 'UploadSourceField' => __DIR__ . '/includes/specials/formfields/UploadSourceField.php', 'UploadStash' => __DIR__ . '/includes/upload/UploadStash.php', diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index 9077666ddf..6f2d72cbe3 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -690,6 +690,14 @@ class MediaWikiServices extends ServiceContainer { return $this->getService( 'ReadOnlyMode' ); } + /** + * @since 1.31 + * @return \UploadRevisionImporter + */ + public function getWikiRevisionUploadImporter() { + return $this->getService( 'UploadRevisionImporter' ); + } + /** * @since 1.30 * @return CommandFactory diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 8b0452db3d..672734dd38 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -442,6 +442,13 @@ return [ ); }, + 'UploadRevisionImporter' => function ( MediaWikiServices $services ) { + return new ImportableUploadRevisionImporter( + $services->getMainConfig()->get( 'EnableUploads' ), + LoggerFactory::getInstance( 'UploadRevisionImporter' ) + ); + }, + 'ShellCommandFactory' => function ( MediaWikiServices $services ) { $config = $services->getMainConfig(); diff --git a/includes/import/ImportableUploadRevision.php b/includes/import/ImportableUploadRevision.php new file mode 100644 index 0000000000..3f60112a0f --- /dev/null +++ b/includes/import/ImportableUploadRevision.php @@ -0,0 +1,68 @@ +enableUploads = $enableUploads; + $this->logger = $logger; + } + + /** + * @return StatusValue + */ + private function newNotOkStatus() { + $statusValue = new StatusValue(); + $statusValue->setOK( false ); + return $statusValue; + } + + public function import( ImportableUploadRevision $importableRevision ) { + # Construct a file + $archiveName = $importableRevision->getArchiveName(); + if ( $archiveName ) { + $this->logger->debug( __METHOD__ . "Importing archived file as $archiveName\n" ); + $file = OldLocalFile::newFromArchiveName( $importableRevision->getTitle(), + RepoGroup::singleton()->getLocalRepo(), $archiveName ); + } else { + $file = wfLocalFile( $importableRevision->getTitle() ); + $file->load( File::READ_LATEST ); + $this->logger->debug( __METHOD__ . 'Importing new file as ' . $file->getName() . "\n" ); + if ( $file->exists() && $file->getTimestamp() > $importableRevision->getTimestamp() ) { + $archiveName = $file->getTimestamp() . '!' . $file->getName(); + $file = OldLocalFile::newFromArchiveName( $importableRevision->getTitle(), + RepoGroup::singleton()->getLocalRepo(), $archiveName ); + $this->logger->debug( __METHOD__ . "File already exists; importing as $archiveName\n" ); + } + } + if ( !$file ) { + $this->logger->debug( __METHOD__ . ': Bad file for ' . $importableRevision->getTitle() . "\n" ); + return $this->newNotOkStatus(); + } + + # Get the file source or download if necessary + $source = $importableRevision->getFileSrc(); + $autoDeleteSource = $importableRevision->isTempSrc(); + if ( !strlen( $source ) ) { + $source = $this->downloadSource( $importableRevision ); + $autoDeleteSource = true; + } + if ( !strlen( $source ) ) { + $this->logger->debug( __METHOD__ . ": Could not fetch remote file.\n" ); + return $this->newNotOkStatus(); + } + + $tmpFile = new TempFSFile( $source ); + if ( $autoDeleteSource ) { + $tmpFile->autocollect(); + } + + $sha1File = ltrim( sha1_file( $source ), '0' ); + $sha1 = $importableRevision->getSha1(); + if ( $sha1 && ( $sha1 !== $sha1File ) ) { + $this->logger->debug( __METHOD__ . ": Corrupt file $source.\n" ); + return $this->newNotOkStatus(); + } + + $user = $importableRevision->getUserObj() ?: User::newFromName( $importableRevision->getUser() ); + + # Do the actual upload + if ( $archiveName ) { + $status = $file->uploadOld( $source, $archiveName, + $importableRevision->getTimestamp(), $importableRevision->getComment(), $user ); + } else { + $flags = 0; + $status = $file->upload( + $source, + $importableRevision->getComment(), + $importableRevision->getComment(), + $flags, + false, + $importableRevision->getTimestamp(), + $user + ); + } + + if ( $status->isGood() ) { + $this->logger->debug( __METHOD__ . ": Successful\n" ); + } else { + $this->logger->debug( __METHOD__ . ': failed: ' . $status->getHTML() . "\n" ); + } + + return $status; + } + + /** + * @deprecated DO NOT CALL ME. + * This method was introduced when factoring UploadImporter out of WikiRevision. + * It only has 1 use by the deprecated downloadSource method in WikiRevision. + * Do not use this in new code. + * + * @param ImportableUploadRevision $wikiRevision + * + * @return bool|string + */ + public function downloadSource( ImportableUploadRevision $wikiRevision ) { + if ( !$this->enableUploads ) { + return false; + } + + $tempo = tempnam( wfTempDir(), 'download' ); + $f = fopen( $tempo, 'wb' ); + if ( !$f ) { + $this->logger->debug( "IMPORT: couldn't write to temp file $tempo\n" ); + return false; + } + + // @todo FIXME! + $src = $wikiRevision->getSrc(); + $data = Http::get( $src, [], __METHOD__ ); + if ( !$data ) { + $this->logger->debug( "IMPORT: couldn't fetch source $src\n" ); + fclose( $f ); + unlink( $tempo ); + return false; + } + + fwrite( $f, $data ); + fclose( $f ); + + return $tempo; + } + +} diff --git a/includes/import/UploadRevisionImporter.php b/includes/import/UploadRevisionImporter.php new file mode 100644 index 0000000000..966fc11a86 --- /dev/null +++ b/includes/import/UploadRevisionImporter.php @@ -0,0 +1,18 @@ +src = $src; @@ -494,7 +496,7 @@ class WikiRevision { /** * @since 1.12.2 - * @return mixed + * @return string|null */ public function getSrc() { return $this->src; @@ -737,106 +739,26 @@ class WikiRevision { /** * @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 ); } } -- 2.20.1