Merge "Pass __METHOD__ to load balancer commit/rollback methods"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 23 Dec 2015 18:48:39 +0000 (18:48 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 23 Dec 2015 18:48:39 +0000 (18:48 +0000)
13 files changed:
includes/DefaultSettings.php
includes/Import.php
includes/api/ApiBase.php
includes/api/ApiRevisionDelete.php
includes/api/ApiTag.php
includes/api/ApiUndelete.php
includes/api/ApiUserrights.php
includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
includes/specials/SpecialPageLanguage.php
languages/i18n/en.json
languages/i18n/qqq.json
resources/src/mediawiki.skinning/elements.css
resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js

index 54216fd..36b6533 100644 (file)
@@ -2609,7 +2609,14 @@ $wgCdnMaxageLagged = 30;
 /**
  * If set, any SquidPurge call on a URL or URLs will send a second purge no less than
  * this many seconds later via the job queue. This requires delayed job support.
- * This should be safely higher than the 'max lag' value in $wgLBFactoryConf.
+ * This should be safely higher than the 'max lag' value in $wgLBFactoryConf, so that
+ * slave lag does not cause page to be stuck in stales states in CDN.
+ *
+ * This also fixes race conditions in two-tiered CDN setups (e.g. cdn2 => cdn1 => MediaWiki).
+ * If a purge for a URL reaches cdn2 before cdn1 and a request reaches cdn2 for that URL,
+ * it will populate the response from the stale cdn1 value. When cdn1 gets the purge, cdn2
+ * will still be stale. If the rebound purge delay is safely higher than the time to relay
+ * a purge to all nodes, then the rebound puge will clear cdn2 after cdn1 was cleared.
  *
  * @since 1.27
  */
index 0999931..67f7ba5 100644 (file)
@@ -825,6 +825,30 @@ class WikiImporter {
         * @return bool|mixed
         */
        private function processRevision( $pageInfo, $revisionInfo ) {
+               global $wgMaxArticleSize;
+
+               // Make sure revisions won't violate $wgMaxArticleSize, which could lead to
+               // database errors and instability. Testing for revisions with only listed
+               // content models, as other content models might use serialization formats
+               // which aren't checked against $wgMaxArticleSize.
+               if ( ( !isset( $revisionInfo['model'] ) ||
+                       in_array( $revisionInfo['model'], array(
+                               'wikitext',
+                               'css',
+                               'json',
+                               'javascript',
+                               'text',
+                               ''
+                       ) ) ) &&
+                       (int)( strlen( $revisionInfo['text'] ) / 1024 ) > $wgMaxArticleSize
+               ) {
+                       throw new MWException( 'The text of ' .
+                               ( isset( $revisionInfo['id'] ) ?
+                                       "the revision with ID $revisionInfo[id]" :
+                                       'a revision'
+                               ) . " exceeds the maximum allowable size ($wgMaxArticleSize KB)" );
+               }
+
                $revision = new WikiRevision( $this->config );
 
                if ( isset( $revisionInfo['id'] ) ) {
index 8a98197..cb74ae1 100644 (file)
@@ -1461,6 +1461,33 @@ abstract class ApiBase extends ContextSource {
                );
        }
 
+       /**
+        * Throw a UsageException, which will (if uncaught) call the main module's
+        * error handler and die with an error message including block info.
+        *
+        * @since 1.27
+        * @param Block $block The block used to generate the UsageException
+        * @throws UsageException always
+        */
+       public function dieBlocked( Block $block ) {
+               // Die using the appropriate message depending on block type
+               if ( $block->getType() == Block::TYPE_AUTO ) {
+                       $this->dieUsage(
+                               'Your IP address has been blocked automatically, because it was used by a blocked user',
+                               'autoblocked',
+                               0,
+                               array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
+                       );
+               } else {
+                       $this->dieUsage(
+                               'You have been blocked from editing',
+                               'blocked',
+                               0,
+                               array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
+                       );
+               }
+       }
+
        /**
         * Get error (as code, string) from a Status object.
         *
index b70b536..4db3ca1 100644 (file)
@@ -36,30 +36,12 @@ class ApiRevisionDelete extends ApiBase {
 
                $params = $this->extractRequestParams();
                $user = $this->getUser();
-
                if ( !$user->isAllowed( RevisionDeleter::getRestriction( $params['type'] ) ) ) {
                        $this->dieUsageMsg( 'badaccess-group0' );
                }
 
                if ( $user->isBlocked() ) {
-                       $block = $user->getBlock();
-
-                       // Die using the appropriate message depending on block type
-                       if ( $block->getType() == TYPE_AUTO ) {
-                               $this->dieUsage(
-                                       'Your IP address has been blocked automatically, because it was used by a blocked user',
-                                       'autoblocked',
-                                       0,
-                                       array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
-                               );
-                       } else {
-                               $this->dieUsage(
-                                       'You have been blocked from editing',
-                                       'blocked',
-                                       0,
-                                       array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
-                               );
-                       }
+                       $this->dieBlocked( $user->getBlock() );
                }
 
                if ( !$params['ids'] ) {
index 4157de0..4bf799e 100644 (file)
@@ -40,24 +40,7 @@ class ApiTag extends ApiBase {
                }
 
                if ( $user->isBlocked() ) {
-                       $block = $user->getBlock();
-
-                       // Die using the appropriate message depending on block type
-                       if ( $block->getType() == TYPE_AUTO ) {
-                               $this->dieUsage(
-                                       'Your IP address has been blocked automatically, because it was used by a blocked user',
-                                       'autoblocked',
-                                       0,
-                                       array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
-                               );
-                       } else {
-                               $this->dieUsage(
-                                       'You have been blocked from editing',
-                                       'blocked',
-                                       0,
-                                       array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) )
-                               );
-                       }
+                       $this->dieBlocked( $user->getBlock() );
                }
 
                // validate and process each revid, rcid and logid
index cd50ee6..469fe7f 100644 (file)
@@ -33,18 +33,13 @@ class ApiUndelete extends ApiBase {
                $this->useTransactionalTimeLimit();
 
                $params = $this->extractRequestParams();
-
-               if ( !$this->getUser()->isAllowed( 'undelete' ) ) {
+               $user = $this->getUser();
+               if ( !$user->isAllowed( 'undelete' ) ) {
                        $this->dieUsageMsg( 'permdenied-undelete' );
                }
 
-               if ( $this->getUser()->isBlocked() ) {
-                       $this->dieUsage(
-                               'You have been blocked from editing',
-                               'blocked',
-                               0,
-                               array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $this->getUser()->getBlock() ) )
-                       );
+               if ( $user->isBlocked() ) {
+                       $this->dieBlocked( $user->getBlock() );
                }
 
                $titleObj = Title::newFromText( $params['title'] );
index 3ccdde2..e32b612 100644 (file)
@@ -49,6 +49,14 @@ class ApiUserrights extends ApiBase {
        }
 
        public function execute() {
+               $pUser = $this->getUser();
+
+               // Deny if the user is blocked and doesn't have the full 'userrights' permission.
+               // This matches what Special:UserRights does for the web UI.
+               if ( $pUser->isBlocked() && !$pUser->isAllowed( 'userrights' ) ) {
+                       $this->dieBlocked( $pUser->getBlock() );
+               }
+
                $params = $this->extractRequestParams();
 
                $user = $this->getUrUser( $params );
index 6705336..04b0434 100644 (file)
@@ -50,14 +50,10 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule {
                // Build CSS rules
                $rules = array();
 
-               // Underline: 2 = browser default, 1 = always, 0 = never
+               // Underline: 2 = skin default, 1 = always, 0 = never
                if ( $options['underline'] < 2 ) {
                        $rules[] = "a { text-decoration: " .
                                ( $options['underline'] ? 'underline' : 'none' ) . "; }";
-               } else {
-                       # The scripts of these languages are very hard to read with underlines
-                       $rules[] = 'a:lang(ar), a:lang(kk-arab), a:lang(mzn), ' .
-                       'a:lang(ps), a:lang(ur) { text-decoration: none; }';
                }
                if ( $options['editfont'] !== 'default' ) {
                        // Double-check that $options['editfont'] consists of safe characters only
@@ -72,6 +68,15 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule {
                return array( 'all' => $style );
        }
 
+       /**
+        * @param ResourceLoaderContext $context
+        * @return bool
+        */
+       public function isKnownEmpty( ResourceLoaderContext $context ) {
+               $styles = $this->getStyles( $context );
+               return isset( $styles['all'] ) && $styles['all'] === '';
+       }
+
        /**
         * @return string
         */
index 9323551..7509bbc 100644 (file)
@@ -101,6 +101,7 @@ class SpecialPageLanguage extends FormSpecialPage {
 
        public function alterForm( HTMLForm $form ) {
                Hooks::run( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
+               $form->setSubmitTextMsg( 'pagelang-submit' );
        }
 
        /**
index 779b8b7..ca4c88e 100644 (file)
        "pagelang-language": "Language",
        "pagelang-use-default": "Use default language",
        "pagelang-select-lang": "Select language",
+       "pagelang-submit": "Submit",
        "right-pagelang": "Change page language",
        "action-pagelang": "change the page language",
        "log-name-pagelang": "Change language log",
index dab2adc..2b54491 100644 (file)
        "pagelang-language": "Language selector label for Special:PageLanguage\n{{Identical|Language}}",
        "pagelang-use-default": "Radio label for selector on Special:PageLanguage for default language",
        "pagelang-select-lang": "Radio label for selector on Special:PageLanguage for language selection\n{{Identical|Select language}}",
+       "pagelang-submit": "Submit button label for Special:PageLanguage form\n{{Identical|Submit}}",
        "right-pagelang": "{{Doc-right|pagelang}}\nRight to change page language on Special:PageLanguage",
        "action-pagelang": "{{Doc-action|pagelang}}",
        "log-name-pagelang": "Display entry for log name for changes in page language in Special:Log.",
index d706d26..7872085 100644 (file)
@@ -25,6 +25,14 @@ a:hover, a:focus {
        text-decoration: underline;
 }
 
+a:lang(ar),
+a:lang(kk-arab),
+a:lang(mzn),
+a:lang(ps),
+a:lang(ur) {
+       text-decoration: none;
+}
+
 a.stub {
        color: #772233;
 }
index e0bbf22..510068a 100644 (file)
                } );
        };
 
+       /**
+        * @inheritdoc
+        */
+       CSP.getItemFromData = function ( data ) {
+               // This is a bit of a hack... We have to canonicalize the data in the same way that
+               // #createItemWidget and CategoryCapsuleItemWidget will do, otherwise we won't find duplicates.
+               data = mw.Title.newFromText( data, NS_CATEGORY ).getMainText();
+               return OO.ui.mixin.GroupElement.prototype.getItemFromData.call( this, data );
+       };
+
        /**
         * Validates the values in `this.searchType`.
         *