Merge "Add hook to allow lazy loading of import sources"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 23 Sep 2015 16:30:36 +0000 (16:30 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 23 Sep 2015 16:30:36 +0000 (16:30 +0000)
1  2 
docs/hooks.txt
includes/DefaultSettings.php
includes/api/ApiImport.php
includes/specials/SpecialImport.php

diff --combined docs/hooks.txt
@@@ -662,8 -662,7 +662,8 @@@ $oldPageID: the page ID of the revisio
  
  'ArticleRevisionVisibilitySet': Called when changing visibility of one or more
  revisions of an article.
 -&$title: Title object of the article
 +$title: Title object of the article
 +$ids: Ids to set the visibility for
  
  'ArticleRollbackComplete': After an article rollback is completed.
  $wikiPage: the WikiPage that was edited
@@@ -1272,21 -1271,20 +1272,21 @@@ $user: User being checke
  $confirmed: Whether or not the email address is confirmed
  
  'EmailUser': Before sending email from one user to another.
 -$to: address of receiving user
 -$from: address of sending user
 +$to: MailAddress object of receiving user
 +$from: MailAddress object of sending user
  $subject: subject of the mail
  $text: text of the mail
 +&$error: Out-param for an error
  
  'EmailUserCC': Before sending the copy of the email to the author.
 -$to: address of receiving user
 -$from: address of sending user
 +$to: MailAddress object of receiving user
 +$from: MailAddress object of sending user
  $subject: subject of the mail
  $text: text of the mail
  
  'EmailUserComplete': After sending email from one user to another.
 -$to: address of receiving user
 -$from: address of sending user
 +$to: MailAddress object of receiving user
 +$from: MailAddress object of sending user
  $subject: subject of the mail
  $text: text of the mail
  
@@@ -1378,9 -1376,6 +1378,9 @@@ $auto: The extracted part of the parse
  $post: Boolean, true if there is text after this autocomment
  $title: An optional title object used to links to sections. Can be null.
  $local: Boolean indicating whether section links should refer to local page.
 +$wikiId: String containing the ID (as used by WikiMap) of the wiki from which the
 +  autocomment originated; null for the local wiki. Added in 1.26, should default
 +  to null in handler functions, for backwards compatibility.
  
  'GalleryGetModes': Get list of classes that can render different modes of a
  gallery.
@@@ -1633,6 -1628,11 +1633,11 @@@ Return false to stop further processin
  $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
@@@ -1846,10 -1846,6 +1851,10 @@@ optional localisation message
  &$ignored: Array of ignored message keys
  &$optional: Array of optional message keys
  
 +'LocalUserCreated': Called when a local user has been created
 +$user: User object for the created user
 +$autocreated: Boolean, whether this was an auto-creation
 +
  'LogEventsListGetExtraInputs': When getting extra inputs to display on
  Special:Log for a specific log type
  $type: String of log type being displayed
@@@ -2185,7 -2181,6 +2190,7 @@@ which depends on user options should in
  the key.
  &$confstr: reference to a hash key string which can be modified
  $user: User (object) requesting the page
 +&$forOptions: array of options the hash is for
  
  'PageViewUpdates': Allow database (or other) changes to be made after a
  page view is seen by MediaWiki.  Note this does not capture views made
@@@ -2417,12 -2412,6 +2422,12 @@@ shown
  $article: the page the form is shown for
  $out: OutputPage object
  
 +'RandomPageQuery': Lets you modify the query used by Special:Random to select
 +random pages.
 +&$tables: Database tables to be used in the query
 +&$conds: Conditions to be applied in the query
 +&$joinConds: Join conditions to be applied in the query
 +
  'RawPageViewBeforeOutput': Right before the text is blown out in action=raw.
  &$obj: RawAction object
  &$text: The text that's going to be the output
@@@ -2454,12 -2443,9 +2459,12 @@@ $context: (IContextSource) The RequestC
  $user: The user having their password expiration reset
  &$newExpire: The new expiration date
  
 -'ResetSessionID': Called from wfResetSessionID
 -$oldSessionID: old session id
 -$newSessionID: new session id
 +'ResourceLoaderForeignApiModules': Called from ResourceLoaderForeignApiModule.
 +Use this to add dependencies to 'mediawiki.ForeignApi' module when you wish
 +to override its behavior. See the module docs for more information.
 +&$dependencies: string[] List of modules that 'mediawiki.ForeignApi' should
 +depend on
 +$context: ResourceLoaderContext|null
  
  'ResourceLoaderGetConfigVars': Called at the end of
  ResourceLoaderStartUpModule::getConfigSettings(). Use this to export static
@@@ -3111,9 -3097,7 +3116,9 @@@ $descriptor: (array) the HTMLForm descr
  
  'UploadFormSourceDescriptors': after the standard source inputs have been
  added to the descriptor
 -$descriptor: (array) the HTMLForm descriptor
 +&$descriptor: (array) the HTMLForm descriptor
 +&$radio: Boolean, if source type should be shown as radio button
 +$selectedSourceType: The selected source type
  
  'UploadVerification': Additional chances to reject an uploaded file. Consider
  using UploadVerifyFile instead.
@@@ -3208,12 -3192,6 +3213,12 @@@ $context: IContextSource objec
  $user: User to get rights for
  &$rights: Current rights
  
 +'UserGroupsChanged': Called after user groups are changed.
 +$user: User whose groups changed
 +$added: Groups added
 +$removed: Groups removed
 +$performer: User who performed the change, false if via autopromotion
 +
  'UserIsBlockedFrom': Check if a user is blocked from a specific page (for
  specific block exemptions).
  $user: User in question
@@@ -3231,14 -3209,6 +3236,14 @@@ $ip: User's IP addres
  false if a UserGetRights hook might remove the named right.
  $right: The user right being checked
  
 +'UserIsHidden': Check if the user's name should be hidden. See User::isHidden().
 +$user: User in question.
 +&$hidden: Set true if the user's name should be hidden.
 +
 +'UserIsLocked': Check if the user is locked. See User::isLocked().
 +$user: User in question.
 +&$locked: Set true if the user should be locked.
 +
  'UserLoadAfterLoadFromSession': Called to authenticate users on external or
  environmental means; occurs after session is loaded.
  $user: user object being loaded
@@@ -3262,9 -3232,6 +3267,9 @@@ database
  $user: User object
  &$options: Options, can be modified.
  
 +'UserLoggedIn': Called after a user is logged in
 +$user: User object for the logged-in user
 +
  'UserLoginComplete': After a user has logged in.
  $user: the user object that was created on login
  $inject_html: Any HTML to inject after the "logged in" message.
@@@ -3310,9 -3277,8 +3315,9 @@@ message(s)
  $user: user retrieving new talks messages
  $talks: array of new talks page(s)
  
 -'UserRights': After a user's group memberships are changed.
 -$user: User object that was changed
 +'UserRights': DEPRECATED! Use UserGroupsChanged instead.
 +After a user's group memberships are changed.
 +&$user: User object that was changed
  $add: Array of strings corresponding to groups added
  $remove: Array of strings corresponding to groups removed
  
@@@ -211,7 -211,7 +211,7 @@@ $wgLoadScript = false
  
  /**
   * The URL path of the skins directory.
 - * Defaults to "{$wgScriptPath}/skins".
 + * Defaults to "{$wgResourceBasePath}/skins".
   * @since 1.3
   */
  $wgStylePath = false;
@@@ -226,7 -226,7 +226,7 @@@ $wgLocalStylePath = false
  
  /**
   * The URL path of the extensions directory.
 - * Defaults to "{$wgScriptPath}/extensions".
 + * Defaults to "{$wgResourceBasePath}/extensions".
   * @since 1.16
   */
  $wgExtensionAssetsPath = false;
@@@ -1860,6 -1860,12 +1860,6 @@@ $wgDBservers = false
   */
  $wgLBFactoryConf = array( 'class' => 'LBFactorySimple' );
  
 -/**
 - * How long to wait for a slave to catch up to the master
 - * @deprecated since 1.24
 - */
 -$wgMasterWaitTimeout = 10;
 -
  /**
   * File to log database errors to
   */
@@@ -2072,14 -2078,6 +2072,14 @@@ $wgMaxArticleSize = 2048
   */
  $wgMemoryLimit = "50M";
  
 +/**
 + * The minimum amount of time that MediaWiki needs for "slow" write request,
 + * particularly ones with multiple non-atomic writes that *should* be as
 + * transactional as possible; MediaWiki will call set_time_limit() if needed.
 + * @since 1.26
 + */
 +$wgTransactionalTimeLimit = 120;
 +
  /** @} */ # end performance hacks }
  
  /************************************************************************//**
@@@ -3473,8 -3471,8 +3473,8 @@@ $wgResourceModuleSkinStyles = array()
  $wgResourceLoaderSources = array();
  
  /**
 - * Default 'remoteBasePath' value for instances of ResourceLoaderFileModule.
 - * If not set, then $wgScriptPath will be used as a fallback.
 + * The default 'remoteBasePath' value for instances of ResourceLoaderFileModule.
 + * Defaults to $wgScriptPath.
   */
  $wgResourceBasePath = null;
  
@@@ -3611,6 -3609,13 +3611,6 @@@ $wgResourceLoaderValidateJS = true
   */
  $wgResourceLoaderValidateStaticJS = false;
  
 -/**
 - * If set to true, asynchronous loading of bottom-queue scripts in the "<head>"
 - * will be enabled. This is an experimental feature that's supposed to make
 - * JavaScript load faster.
 - */
 -$wgResourceLoaderExperimentalAsyncLoading = false;
 -
  /**
   * Global LESS variables. An associative array binding variable names to
   * LESS code snippets representing their values.
   */
  $wgResourceLoaderLESSVars = array();
  
 -/**
 - * Custom LESS functions. An associative array mapping function name to PHP
 - * callable.
 - *
 - * Changes to LESS functions do not trigger cache invalidation.
 - *
 - * @since 1.22
 - * @deprecated since 1.24 Questionable usefulness and problematic to support,
 - *     will be removed in the future.
 - */
 -$wgResourceLoaderLESSFunctions = array();
 -
  /**
   * Default import paths for LESS modules. LESS files referenced in @import
   * statements will be looked up here first, and relative to the importing file
@@@ -3708,8 -3725,8 +3708,8 @@@ $wgMetaNamespaceTalk = false
   * Additional namespaces. If the namespaces defined in Language.php and
   * Namespace.php are insufficient, you can create new ones here, for example,
   * to import Help files in other languages. You can also override the namespace
 - * names of existing namespaces. Extensions developers should use
 - * $wgCanonicalNamespaceNames.
 + * names of existing namespaces. Extensions should use the CanonicalNamespaces
 + * hook or extension.json.
   *
   * @warning Once you delete a namespace, the pages in that namespace will
   * no longer be accessible. If you rename it, then you can access them through
@@@ -4104,55 -4121,44 +4104,55 @@@ $wgEnableImageWhitelist = true
  $wgAllowImageTag = false;
  
  /**
 - * $wgUseTidy: use tidy to make sure HTML output is sane.
 - * Tidy is a free tool that fixes broken HTML.
 - * See http://www.w3.org/People/Raggett/tidy/
 + * Configuration for HTML postprocessing tool. Set this to a configuration
 + * array to enable an external tool. Dave Raggett's "HTML Tidy" is typically
 + * used. See http://www.w3.org/People/Raggett/tidy/
 + *
 + * If this is null and $wgUseTidy is true, the deprecated configuration
 + * parameters will be used instead.
 + *
 + * If this is null and $wgUseTidy is false, a pure PHP fallback will be used.
   *
 - * - $wgTidyBin should be set to the path of the binary and
 - * - $wgTidyConf to the path of the configuration file.
 - * - $wgTidyOpts can include any number of parameters.
 - * - $wgTidyInternal controls the use of the PECL extension or the
 - *   libtidy (PHP >= 5) extension to use an in-process tidy library instead
 - *   of spawning a separate program.
 - *   Normally you shouldn't need to override the setting except for
 - *   debugging. To install, use 'pear install tidy' and add a line
 - *   'extension=tidy.so' to php.ini.
 + * Keys are:
 + *  - driver: May be:
 + *    - RaggettInternalHHVM: Use the limited-functionality HHVM extension
 + *    - RaggettInternalPHP: Use the PECL extension
 + *    - RaggettExternal: Shell out to an external binary (tidyBin)
 + *
 + *  - tidyConfigFile: Path to configuration file for any of the Raggett drivers
 + *  - debugComment: True to add a comment to the output with warning messages
 + *  - tidyBin: For RaggettExternal, the path to the tidy binary.
 + *  - tidyCommandLine: For RaggettExternal, additional command line options.
   */
 -$wgUseTidy = false;
 +$wgTidyConfig = null;
  
  /**
 - * @see $wgUseTidy
 + * Set this to true to use the deprecated tidy configuration parameters.
 + * @deprecated use $wgTidyConfig
   */
 -$wgAlwaysUseTidy = false;
 +$wgUseTidy = false;
  
  /**
 - * @see $wgUseTidy
 + * The path to the tidy binary.
 + * @deprecated Use $wgTidyConfig['tidyBin']
   */
  $wgTidyBin = 'tidy';
  
  /**
 - * @see $wgUseTidy
 + * The path to the tidy config file
 + * @deprecated Use $wgTidyConfig['tidyConfigFile']
   */
 -$wgTidyConf = $IP . '/includes/tidy.conf';
 +$wgTidyConf = $IP . '/includes/tidy/tidy.conf';
  
  /**
 - * @see $wgUseTidy
 + * The command line options to the tidy binary
 + * @deprecated Use $wgTidyConfig['tidyCommandLine']
   */
  $wgTidyOpts = '';
  
  /**
 - * @see $wgUseTidy
 + * Set this to true to use the tidy extension
 + * @deprecated Use $wgTidyConfig['driver']
   */
  $wgTidyInternal = extension_loaded( 'tidy' );
  
@@@ -6363,8 -6369,8 +6363,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,
   *     );
   * @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.
   */
@@@ -6933,6 -6942,7 +6936,6 @@@ $wgLogHeaders = array
   */
  $wgLogActions = array(
        'protect/modify' => 'modifiedarticleprotection',
 -      'protect/move_prot' => 'movedarticleprotection',
        'protect/protect' => 'protectedarticle',
        'protect/unprotect' => 'unprotectedarticle',
  );
@@@ -6962,7 -6972,6 +6965,7 @@@ $wgLogActionsHandlers = array
        'move/move' => 'MoveLogFormatter',
        'move/move_redir' => 'MoveLogFormatter',
        'patrol/patrol' => 'PatrolLogFormatter',
 +      'protect/move_prot' => 'ProtectLogFormatter',
        'rights/autopromote' => 'RightsLogFormatter',
        'rights/rights' => 'RightsLogFormatter',
        'suppress/block' => 'BlockLogFormatter',
@@@ -7236,6 -7245,12 +7239,6 @@@ $wgAPIPropModules = array()
   */
  $wgAPIListModules = array();
  
 -/**
 - * This variable is ignored. To add your module to the API, please add it to $wgAPI*Modules
 - * @deprecated since 1.21
 - */
 -$wgAPIGeneratorModules = array();
 -
  /**
   * Maximum amount of rows to scan in a DB query in the API
   * The default value is generally fine
@@@ -7686,7 -7701,6 +7689,7 @@@ $wgUseLinkNamespaceDBFields = true
   *   $wgVirtualRestConfig['modules']['parsoid'] = array(
   *     'url' => 'http://localhost:8000',
   *     'prefix' => 'enwiki',
 + *     'domain' => 'en.wikipedia.org',
   *   );
   *
   * @var array
@@@ -7697,7 -7711,6 +7700,7 @@@ $wgVirtualRestConfig = array
        'global' => array(
                # Timeout in seconds
                'timeout' => 360,
 +              # 'domain' is set to $wgCanonicalServer in Setup.php
                'forwardCookies' => false,
                'HTTPProxy' => null
        )
@@@ -32,8 -32,6 +32,8 @@@
  class ApiImport extends ApiBase {
  
        public function execute() {
 +              $this->useTransactionalTimeLimit();
 +
                $user = $this->getUser();
                $params = $this->extractRequestParams();
  
                $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;
        }
                                ApiBase::PARAM_TYPE => 'upload',
                        ),
                        'interwikisource' => array(
-                               ApiBase::PARAM_TYPE => $this->getConfig()->get( 'ImportSources' ),
+                               ApiBase::PARAM_TYPE => $this->getAllowedImportSources(),
                        ),
                        'interwikipage' => null,
                        'fullhistory' => false,
@@@ -42,6 -42,7 +42,7 @@@ class SpecialImport extends SpecialPag
        private $history = true;
        private $includeTemplates = false;
        private $pageLinkDepth;
+       private $importSources;
  
        /**
         * Constructor
@@@ -57,8 -58,6 +58,8 @@@
         * @throws ReadOnlyError
         */
        function execute( $par ) {
 +              $this->useTransactionalTimeLimit();
 +
                $this->setHeaders();
                $this->outputHeader();
  
@@@ -66,6 -65,9 +67,9 @@@
  
                $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' );
                        }
                        $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' );
                $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' );
                                        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 ) {
                        );
  
                        $needSubprojectField = false;
-                       foreach ( $importSources as $key => $value ) {
+                       foreach ( $this->importSources as $key => $value ) {
                                if ( is_int( $key ) ) {
                                        $key = $value;
                                } elseif ( $value !== $key ) {
                                );
  
                                $subprojectsToAdd = array();
-                               foreach ( $importSources as $key => $value ) {
+                               foreach ( $this->importSources as $key => $value ) {
                                        if ( is_array( $value ) ) {
                                                $subprojectsToAdd = array_merge( $subprojectsToAdd, $value );
                                        }