Add hook to allow lazy loading of import sources
authorThis, that and the other <at.light@live.com.au>
Wed, 23 Sep 2015 07:54:31 +0000 (17:54 +1000)
committerThis, that and the other <at.light@live.com.au>
Wed, 23 Sep 2015 07:54:31 +0000 (17:54 +1000)
Currently import sources have to be set into $wgImportSources as part of
wiki startup. This is not practical for the WMF cluster, where we need some
reasonably complex logic to set up the import source structure.

This change allows the import source list to be populated from a new
"ImportSources" hook. This hook is only called when the list of import
sources is actually needed (namely, when a user with relevant permissions
loads Special:Import).

Bug: T17583
Change-Id: Ice9a19cb6dfe53ae72aa71353d0553ee9338f233

docs/hooks.txt
includes/DefaultSettings.php
includes/api/ApiImport.php
includes/specials/SpecialImport.php

index 65ae988..ab8dbed 100644 (file)
@@ -1628,6 +1628,11 @@ Return false to stop further processing of the tag
 $reader: XMLReader object
 $revisionInfo: Array of information
 
+'ImportSources': Called when reading from the $wgImportSources configuration
+variable. Can be used to lazy-load the import sources list.
+&$importSources: The value of $wgImportSources. Modify as necessary. See the
+comment in DefaultSettings.php for the detail of how to structure this array.
+
 'InfoAction': When building information to display on the action=info page.
 $context: IContextSource object
 &$pageInfo: Array of information
index 19d4b89..c15c090 100644 (file)
@@ -6369,8 +6369,8 @@ $wgShowCreditsIfMax = true;
 
 /**
  * List of interwiki prefixes for wikis we'll accept as sources for
- * Special:Import (for sysops). Since complete page history can be imported,
- * these should be 'trusted'.
+ * Special:Import and API action=import. Since complete page history can be
+ * imported, these should be 'trusted'.
  *
  * This can either be a regular array, or an associative map specifying
  * subprojects on the interwiki map of the target wiki, or a mix of the two,
@@ -6383,6 +6383,9 @@ $wgShowCreditsIfMax = true;
  *     );
  * @endcode
  *
+ * If you have a very complex import sources setup, you can lazy-load it using
+ * the ImportSources hook.
+ *
  * If a user has the 'import' permission but not the 'importupload' permission,
  * they will only be able to run imports through this transwiki interface.
  */
index 4154083..f4f56d0 100644 (file)
@@ -90,6 +90,30 @@ class ApiImport extends ApiBase {
                $result->addValue( null, $this->getModuleName(), $resultData );
        }
 
+       /**
+        * Returns a list of interwiki prefixes corresponding to each defined import
+        * source.
+        *
+        * @return array
+        * @since 1.26
+        */
+       public function getAllowedImportSources() {
+               $importSources = $this->getConfig()->get( 'ImportSources' );
+               Hooks::run( 'ImportSources', array( &$importSources ) );
+
+               $result = array();
+               foreach ( $importSources as $key => $value ) {
+                       if ( is_int( $key ) ) {
+                               $result[] = $value;
+                       } else {
+                               foreach ( $value as $subproject ) {
+                                       $result[] = "$key:$subproject";
+                               }
+                       }
+               }
+               return $result;
+       }
+
        public function mustBePosted() {
                return true;
        }
@@ -105,7 +129,7 @@ class ApiImport extends ApiBase {
                                ApiBase::PARAM_TYPE => 'upload',
                        ),
                        'interwikisource' => array(
-                               ApiBase::PARAM_TYPE => $this->getConfig()->get( 'ImportSources' ),
+                               ApiBase::PARAM_TYPE => $this->getAllowedImportSources(),
                        ),
                        'interwikipage' => null,
                        'fullhistory' => false,
index f9b8ac3..28ae05d 100644 (file)
@@ -42,6 +42,7 @@ class SpecialImport extends SpecialPage {
        private $history = true;
        private $includeTemplates = false;
        private $pageLinkDepth;
+       private $importSources;
 
        /**
         * Constructor
@@ -64,6 +65,9 @@ class SpecialImport extends SpecialPage {
 
                $this->getOutput()->addModules( 'mediawiki.special.import' );
 
+               $this->importSources = $this->getConfig()->get( 'ImportSources' );
+               Hooks::run( 'ImportSources', array( &$this->importSources ) );
+
                $user = $this->getUser();
                if ( !$user->isAllowedAny( 'import', 'importupload' ) ) {
                        throw new PermissionsError( 'import' );
@@ -134,16 +138,17 @@ class SpecialImport extends SpecialPage {
                        }
                        $this->interwiki = $this->fullInterwikiPrefix = $request->getVal( 'interwiki' );
                        // does this interwiki have subprojects?
-                       $importSources = $this->getConfig()->get( 'ImportSources' );
-                       $hasSubprojects = array_key_exists( $this->interwiki, $importSources );
-                       if ( !$hasSubprojects && !in_array( $this->interwiki, $importSources ) ) {
+                       $hasSubprojects = array_key_exists( $this->interwiki, $this->importSources );
+                       if ( !$hasSubprojects && !in_array( $this->interwiki, $this->importSources ) ) {
                                $source = Status::newFatal( "import-invalid-interwiki" );
                        } else {
                                if ( $hasSubprojects ) {
                                        $this->subproject = $request->getVal( 'subproject' );
                                        $this->fullInterwikiPrefix .= ':' . $request->getVal( 'subproject' );
                                }
-                               if ( $hasSubprojects && !in_array( $this->subproject, $importSources[$this->interwiki] ) ) {
+                               if ( $hasSubprojects &&
+                                       !in_array( $this->subproject, $this->importSources[$this->interwiki] )
+                               ) {
                                        $source = Status::newFatal( "import-invalid-interwiki" );
                                } else {
                                        $this->history = $request->getCheck( 'interwikiHistory' );
@@ -304,7 +309,6 @@ class SpecialImport extends SpecialPage {
                $user = $this->getUser();
                $out = $this->getOutput();
                $this->addHelpLink( '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Import', true );
-               $importSources = $this->getConfig()->get( 'ImportSources' );
 
                if ( $user->isAllowed( 'importupload' ) ) {
                        $mappingSelection = $this->getMappingFormPart( 'upload' );
@@ -354,12 +358,12 @@ class SpecialImport extends SpecialPage {
                                        Xml::closeElement( 'fieldset' )
                        );
                } else {
-                       if ( empty( $importSources ) ) {
+                       if ( empty( $this->importSources ) ) {
                                $out->addWikiMsg( 'importnosources' );
                        }
                }
 
-               if ( $user->isAllowed( 'import' ) && !empty( $importSources ) ) {
+               if ( $user->isAllowed( 'import' ) && !empty( $this->importSources ) ) {
                        # Show input field for import depth only if $wgExportMaxLinkDepth > 0
                        $importDepth = '';
                        if ( $this->getConfig()->get( 'ExportMaxLinkDepth' ) > 0 ) {
@@ -401,7 +405,7 @@ class SpecialImport extends SpecialPage {
                        );
 
                        $needSubprojectField = false;
-                       foreach ( $importSources as $key => $value ) {
+                       foreach ( $this->importSources as $key => $value ) {
                                if ( is_int( $key ) ) {
                                        $key = $value;
                                } elseif ( $value !== $key ) {
@@ -433,7 +437,7 @@ class SpecialImport extends SpecialPage {
                                );
 
                                $subprojectsToAdd = array();
-                               foreach ( $importSources as $key => $value ) {
+                               foreach ( $this->importSources as $key => $value ) {
                                        if ( is_array( $value ) ) {
                                                $subprojectsToAdd = array_merge( $subprojectsToAdd, $value );
                                        }