From e421c99e870462474a0298e1a330a308bc77f874 Mon Sep 17 00:00:00 2001 From: umherirrender Date: Wed, 15 Aug 2012 10:07:26 +0200 Subject: [PATCH] Allow importing pages as subpage Adding a "root page" input to Special:Import, which is used as prefix before each imported page. With this option, it is possible to import pages as subpage of a user or a project page. On de.wp the import is often done into a low used namespace (100 or 101) and than moved to the user space. Doing this in one step, makes things easier. Change-Id: Id5dbf742295a1bbddd8cb6eaa09fb28051f26613 --- RELEASE-NOTES-1.20 | 1 + includes/Import.php | 38 ++++++++++++++++++++++++++++- includes/api/ApiBase.php | 2 ++ includes/api/ApiImport.php | 12 ++++++++- includes/specials/SpecialImport.php | 32 ++++++++++++++++++++++-- languages/messages/MessagesEn.php | 4 +++ languages/messages/MessagesQqq.php | 4 +++ 7 files changed, 89 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES-1.20 b/RELEASE-NOTES-1.20 index 6f45cf052d..54554c94e2 100644 --- a/RELEASE-NOTES-1.20 +++ b/RELEASE-NOTES-1.20 @@ -122,6 +122,7 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki. API upload errors due to the file extension blacklist. * jsMessage: Redesigned in Vector/Monobook as floating bubble with auto-hide. * New hook 'ParserTestGlobals' allows to set globals before running parser tests. +* Allow importing pages as subpage. === Bug fixes in 1.20 === * (bug 30245) Use the correct way to construct a log page title. diff --git a/includes/Import.php b/includes/Import.php index 491ec0936e..11f379522d 100644 --- a/includes/Import.php +++ b/includes/Import.php @@ -33,7 +33,7 @@ class WikiImporter { private $reader = null; private $mLogItemCallback, $mUploadCallback, $mRevisionCallback, $mPageCallback; - private $mSiteInfoCallback, $mTargetNamespace, $mPageOutCallback; + private $mSiteInfoCallback, $mTargetNamespace, $mTargetRootPage, $mPageOutCallback; private $mNoticeCallback, $mDebug; private $mImportUploads, $mImageBasePath; private $mNoUpdates = false; @@ -199,6 +199,39 @@ class WikiImporter { } } + /** + * Set a target root page under which all pages are imported + * @param $rootpage + * @return status object + */ + public function setTargetRootPage( $rootpage ) { + $status = Status::newGood(); + if( is_null( $rootpage ) ) { + // No rootpage + $this->mTargetRootPage = null; + } elseif( $rootpage !== '' ) { + $rootpage = rtrim( $rootpage, '/' ); //avoid double slashes + $title = Title::newFromText( $rootpage, !is_null( $this->mTargetNamespace ) ? $this->mTargetNamespace : NS_MAIN ); + if( !$title || $title->isExternal() ) { + $status->fatal( 'import-rootpage-invalid' ); + } else { + if( !MWNamespace::hasSubpages( $title->getNamespace() ) ) { + global $wgContLang; + + $displayNSText = $title->getNamespace() == NS_MAIN + ? wfMessage( 'blanknamespace' )->text() + : $wgContLang->getNsText( $title->getNamespace() ); + $status->fatal( 'import-rootpage-nosubpage', $displayNSText ); + } else { + // set namespace to 'all', so the namespace check in processTitle() can passed + $this->setTargetNamespace( null ); + $this->mTargetRootPage = $title->getPrefixedDBKey(); + } + } + } + return $status; + } + /** * @param $dir */ @@ -791,6 +824,9 @@ class WikiImporter { $title = Title::makeTitleSafe( $this->mTargetNamespace, $origTitle->getDBkey() ); } else { + if( !is_null( $this->mTargetRootPage ) ) { + $workTitle = $this->mTargetRootPage . '/' . $workTitle; + } $title = Title::newFromText( $workTitle ); } diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index 59a4ef9064..ca9f73869c 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -1270,6 +1270,8 @@ abstract class ApiBase extends ContextSource { 'nouserspecified' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ), 'noname' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ), 'summaryrequired' => array( 'code' => 'summaryrequired', 'info' => 'Summary required' ), + 'import-rootpage-invalid' => array( 'code' => 'import-rootpage-invalid', 'info' => 'Root page is an invalid title' ), + 'import-rootpage-nosubpage' => array( 'code' => 'import-rootpage-nosubpage', 'info' => 'Namespace "$1" of the root page does not allow subpages' ), // API-specific messages 'readrequired' => array( 'code' => 'readapidenied', 'info' => "You need read permission to use this module" ), diff --git a/includes/api/ApiImport.php b/includes/api/ApiImport.php index abd2777189..637c1fff7f 100644 --- a/includes/api/ApiImport.php +++ b/includes/api/ApiImport.php @@ -68,6 +68,12 @@ class ApiImport extends ApiBase { if ( isset( $params['namespace'] ) ) { $importer->setTargetNamespace( $params['namespace'] ); } + if ( isset( $params['rootpage'] ) ) { + $statusRootPage = $importer->setTargetRootPage( $params['rootpage'] ); + if( !$statusRootPage->isGood() ) { + $this->dieUsageMsg( $statusRootPage->getErrorsArray() ); + } + } $reporter = new ApiImportReporter( $importer, $isUpload, @@ -112,7 +118,8 @@ class ApiImport extends ApiBase { 'templates' => false, 'namespace' => array( ApiBase::PARAM_TYPE => 'namespace' - ) + ), + 'rootpage' => null, ); } @@ -126,6 +133,7 @@ class ApiImport extends ApiBase { 'fullhistory' => 'For interwiki imports: import the full history, not just the current version', 'templates' => 'For interwiki imports: import all included templates as well', 'namespace' => 'For interwiki imports: import to this namespace', + 'rootpage' => 'Import as subpage of this page', ); } @@ -155,6 +163,8 @@ class ApiImport extends ApiBase { array( 'cantimport-upload' ), array( 'import-unknownerror', 'source' ), array( 'import-unknownerror', 'result' ), + array( 'import-rootpage-nosubpage', 'namespace' ), + array( 'import-rootpage-invalid' ), ) ); } diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php index 873c9c6d8f..362fc5cf4c 100644 --- a/includes/specials/SpecialImport.php +++ b/includes/specials/SpecialImport.php @@ -33,6 +33,7 @@ class SpecialImport extends SpecialPage { private $interwiki = false; private $namespace; + private $rootpage = ''; private $frompage = ''; private $logcomment= false; private $history = true; @@ -100,6 +101,7 @@ class SpecialImport extends SpecialPage { $this->logcomment = $request->getText( 'log-comment' ); $this->pageLinkDepth = $wgExportMaxLinkDepth == 0 ? 0 : $request->getIntOrNull( 'pagelink-depth' ); + $this->rootpage = $request->getText( 'rootpage' ); $user = $this->getUser(); if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) { @@ -137,12 +139,20 @@ class SpecialImport extends SpecialPage { if( !$source->isGood() ) { $out->wrapWikiMsg( "

\n$1\n

", array( 'importfailed', $source->getWikiText() ) ); } else { - $out->addWikiMsg( "importstart" ); - $importer = new WikiImporter( $source->value ); if( !is_null( $this->namespace ) ) { $importer->setTargetNamespace( $this->namespace ); } + if( !is_null( $this->rootpage ) ) { + $statusRootPage = $importer->setTargetRootPage( $this->rootpage ); + if( !$statusRootPage->isGood() ) { + $out->wrapWikiMsg( "

\n$1\n

", array( 'import-options-wrong', $statusRootPage->getWikiText(), count( $statusRootPage->getErrorsArray() ) ) ); + return; + } + } + + $out->addWikiMsg( "importstart" ); + $reporter = new ImportReporter( $importer, $isUpload, $this->interwiki , $this->logcomment); $reporter->setContext( $this->getContext() ); $exception = false; @@ -203,6 +213,15 @@ class SpecialImport extends SpecialPage { array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' . " + + " . + Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage' ) . + " + " . + Xml::input( 'rootpage', 50, $this->rootpage, + array( 'id' => 'mw-interwiki-rootpage', 'type' => 'text' ) ) . ' ' . + " + " . @@ -300,6 +319,15 @@ class SpecialImport extends SpecialPage { array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' . " + + " . + Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage' ) . + " + " . + Xml::input( 'rootpage', 50, $this->rootpage, + array( 'id' => 'mw-interwiki-rootpage', 'type' => 'text' ) ) . ' ' . + " + diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 81b4f23b5a..1857ed8ce9 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -3465,6 +3465,7 @@ All transwiki import actions are logged at the [[Special:Log/import|import log]] 'import-interwiki-templates' => 'Include all templates', 'import-interwiki-submit' => 'Import', 'import-interwiki-namespace' => 'Destination namespace:', +'import-interwiki-rootpage' => 'Destination root page (optional):', 'import-upload-filename' => 'Filename:', 'import-comment' => 'Comment:', 'importtext' => 'Please export the file from the source wiki using the [[Special:Export|export utility]]. @@ -3501,6 +3502,9 @@ Please try again.', 'import-error-interwiki' => 'Page "$1" is not imported because its name is reserved for external linking (interwiki).', 'import-error-special' => 'Page "$1" is not imported because it belongs to a special namespace that does not allow pages.', 'import-error-invalid' => 'Page "$1" is not imported because its name is invalid.', +'import-options-wrong' => 'Wrong {{PLURAL:$2|option|options}}: $1', +'import-rootpage-invalid' => 'Given root page is an invalid title.', +'import-rootpage-nosubpage' => 'Namespace "$1" of the root page does not allow subpages.', # Import log 'importlogpage' => 'Import log', diff --git a/languages/messages/MessagesQqq.php b/languages/messages/MessagesQqq.php index 25e9d81fbf..3a0f5d9e1b 100644 --- a/languages/messages/MessagesQqq.php +++ b/languages/messages/MessagesQqq.php @@ -3234,6 +3234,7 @@ Tooltip shown when hovering over a little sign of a thumb image, to go to the im 'import' => 'The title of the special page [[Special:Import]];', 'import-interwiki-history' => 'This is an option on [[Special:Import]]. Usually, when unchecked, only the first version of a page is imported. When you check the option, all versions are imported. This is important often to check for licensing reasons.', 'import-interwiki-submit' => '{{Identical|Import}}', +'import-interwiki-rootpage' => 'Used on [[Special:Import]] as label', 'import-upload-filename' => 'Used on [[Special:Import]] as label for upload of an XML file containing the pages to import.', 'xml-error-string' => ':$1: Some kind of message, perhaps name of the error? :$2: line number @@ -3254,6 +3255,9 @@ See also: * $1 is a page name. See also: * {{msg-mw|import-error-edit}}', +'import-options-wrong' => 'Used on [[Special:Import]], when one of the options has an error.', +'import-rootpage-invalid' => 'Used on [[Special:Import]], when the root page is invalid.', +'import-rootpage-nosubpage' => 'Used on [[Special:Import]], when the import namespace does not support subpages.', # Import log 'importlogpage' => '{{doc-logpage}}', -- 2.20.1