* Updated mediawiki/mediawiki-codesniffer from v20.0.0 to v21.0.0.
* Updated composer/spdx-licenses from 1.3.0 to 1.4.0.
* Updated jquery.i18n from 1.0.4 to 1.0.5.
-* Updated wikimedia/timestamp from 1.0.0 to 2.0.0.
+* Updated wikimedia/timestamp from 1.0.0 to 2.2.0.
* Updated wikimedia/remex-html from 1.0.3 to 2.0.0.
* Updated jquery from v3.2.1 to v3.3.1.
content is not being preserved. 'fromsection-{slot}' and 'tosection-{slot}'
instead expand the given text as if for a section edit. This effectively
declines T183823 in favor of T185723.
+* (T198214) The 'disabletidy' parameter to action=parse has been
+ deprecated; untidy output will not be supported by future wikitext
+ parsers.
=== Action API internal changes in 1.32 ===
* Added 'ApiParseMakeOutputPage' hook.
* Parameter names may no longer contain '{' or '}', as these are now used for
templated parameters.
* (T194950) Added 'ApiMaxLagInfo' hook.
-* Added 'ApiParseMakeOutputPage' hook.
* The following methods now take a RevisionRecord rather than a Revision. No
external callers are known.
* ApiFeedContributions::feedItemAuthor()
Wikimedia\Rdbms\LBFactory.
* The MimeMagic class, deprecated since 1.28 has been removed. Get a
MimeAnalyzer instance from MediaWikiServices instead.
+* The '--tidy' option to maintenance/parse.php has been removed. Tidying
+ the output is now the default. Use '--no-tidy' to bypass the tidy
+ phase.
=== Deprecations in 1.32 ===
* HTMLForm::setSubmitProgressive() is deprecated. No need to call it. Submit
'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php',
'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php',
'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php',
+ 'EmptyUserGroup' => __DIR__ . '/maintenance/emptyUserGroup.php',
'EnConverter' => __DIR__ . '/languages/classes/LanguageEn.php',
'EncryptedPassword' => __DIR__ . '/includes/password/EncryptedPassword.php',
'EnhancedChangesList' => __DIR__ . '/includes/changes/EnhancedChangesList.php',
'MappedIterator' => __DIR__ . '/includes/libs/MappedIterator.php',
'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
'McTest' => __DIR__ . '/maintenance/mctest.php',
+ 'McrRestoreAction' => __DIR__ . '/includes/actions/McrRestoreAction.php',
'McrUndoAction' => __DIR__ . '/includes/actions/McrUndoAction.php',
'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
"wikimedia/running-stat": "1.2.1",
"wikimedia/scoped-callback": "2.0.0",
"wikimedia/utfnormal": "2.0.0",
- "wikimedia/timestamp": "2.1.1",
+ "wikimedia/timestamp": "2.2.0",
"wikimedia/wait-condition-loop": "1.0.1",
"wikimedia/wrappedstring": "3.0.1",
"wikimedia/xmp-reader": "0.6.0",
/**
* MySQL table options to use during installation or update
*/
-$wgDBTableOptions = 'ENGINE=InnoDB';
+$wgDBTableOptions = 'ENGINE=InnoDB, DEFAULT CHARSET=binary';
/**
* SQL Mode - default is turning off all modes, including strict, if set.
'info' => true,
'markpatrolled' => true,
'mcrundo' => McrUndoAction::class,
+ 'mcrrestore' => McrRestoreAction::class,
'protect' => true,
'purge' => true,
'raw' => true,
!$undorev->isDeleted( Revision::DELETED_TEXT ) &&
!$oldrev->isDeleted( Revision::DELETED_TEXT )
) {
- if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev ) ) {
+ if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev )
+ || !$this->isSupportedContentModel( $oldrev->getContentModel() )
+ ) {
// Hack for undo while EditPage can't handle multi-slot editing
$this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
'action' => 'mcrundo',
$this->context->msg( 'undo-' . $undoMsg )->plain() . '</div>', true, /* interface */true );
}
+ if ( $content === false ) {
+ // Hack for restoring old revisions while EditPage
+ // can't handle multi-slot editing.
+
+ $curRevision = $this->page->getRevision();
+ $oldRevision = $this->mArticle->getRevisionFetched();
+
+ if ( $curRevision
+ && $oldRevision
+ && $curRevision->getId() !== $oldRevision->getId()
+ && ( WikiPage::hasDifferencesOutsideMainSlot( $oldRevision, $curRevision )
+ || !$this->isSupportedContentModel( $oldRevision->getContentModel() ) )
+ ) {
+ $this->context->getOutput()->redirect(
+ $this->mTitle->getFullURL(
+ [
+ 'action' => 'mcrrestore',
+ 'restore' => $oldRevision->getId(),
+ ]
+ )
+ );
+
+ return false;
+ }
+ }
+
if ( $content === false ) {
$content = $this->getOriginalContent( $user );
}
* @return EventRelayerGroup
*/
public static function singleton() {
+ wfDeprecated( __METHOD__, '1.27' );
return MediaWikiServices::getInstance()->getEventRelayerGroup();
}
--- /dev/null
+<?php
+/**
+ * Temporary action for restoring multi-content revisions
+ * @file
+ * @ingroup Actions
+ */
+
+/**
+ * Temporary action for restoring multi-content revisions.
+ *
+ * This is intended to go away when real MCR support is added to EditPage and
+ * the standard revert-by-edit behavior can be implemented there instead.
+ *
+ * @ingroup Actions
+ * @since 1.32
+ * @deprecated since 1.32
+ */
+class McrRestoreAction extends McrUndoAction {
+
+ public function getName() {
+ return 'mcrrestore';
+ }
+
+ public function getDescription() {
+ return '';
+ }
+
+ protected function initFromParameters() {
+ $curRev = $this->page->getRevision();
+ if ( !$curRev ) {
+ throw new ErrorPageError( 'mcrundofailed', 'nopagetext' );
+ }
+ $this->curRev = $curRev->getRevisionRecord();
+ $this->cur = $this->getRequest()->getInt( 'cur', $this->curRev->getId() );
+
+ $this->undo = $this->cur;
+ $this->undoafter = $this->getRequest()->getInt( 'restore' );
+
+ if ( $this->undo == 0 || $this->undoafter == 0 ) {
+ throw new ErrorPageError( 'mcrundofailed', 'mcrundo-missingparam' );
+ }
+ }
+
+ protected function addStatePropagationFields( HTMLForm $form ) {
+ $form->addHiddenField( 'restore', $this->undoafter );
+ $form->addHiddenField( 'cur', $this->curRev->getId() );
+ }
+
+ protected function alterForm( HTMLForm $form ) {
+ parent::alterForm( $form );
+
+ $form->setWrapperLegendMsg( 'confirm-mcrrestore-title' );
+ }
+
+}
*/
class McrUndoAction extends FormAction {
- private $undo = 0, $undoafter = 0, $cur = 0;
+ protected $undo = 0, $undoafter = 0, $cur = 0;
/** @param RevisionRecord|null */
- private $curRev = null;
+ protected $curRev = null;
public function getName() {
return 'mcrundo';
parent::show();
}
- protected function checkCanExecute( User $user ) {
- parent::checkCanExecute( $user );
-
+ protected function initFromParameters() {
$this->undoafter = $this->getRequest()->getInt( 'undoafter' );
$this->undo = $this->getRequest()->getInt( 'undo' );
}
$this->curRev = $curRev->getRevisionRecord();
$this->cur = $this->getRequest()->getInt( 'cur', $this->curRev->getId() );
+ }
+
+ protected function checkCanExecute( User $user ) {
+ parent::checkCanExecute( $user );
+
+ $this->initFromParameters();
$revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup();
'attribs' => Linker::tooltipAndAccesskeyAttribs( 'diff' ),
] );
+ $this->addStatePropagationFields( $form );
+ }
+
+ protected function addStatePropagationFields( HTMLForm $form ) {
$form->addHiddenField( 'undo', $this->undo );
$form->addHiddenField( 'undoafter', $this->undoafter );
$form->addHiddenField( 'cur', $this->curRev->getId() );
],
'disablelimitreport' => false,
'disableeditsection' => false,
- 'disabletidy' => false,
+ 'disabletidy' => [
+ ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_DEPRECATED => true, // Since 1.32
+ ],
'disablestylededuplication' => false,
'generatexml' => [
ApiBase::PARAM_DFLT => false,
$this->parserTitle = Title::newFromText( 'Installer' );
$this->parserOptions = new ParserOptions( $wgUser ); // language will be wrong :(
+ $this->parserOptions->setTidy( true );
// Don't try to access DB before user language is initialised
$this->setParserLanguage( Language::factory( 'en' ) );
}
public function execute() {
$text = $this->getFileContents();
$text = InstallDocFormatter::format( $text );
- $this->parent->output->addWikiText( $text );
+ $this->parent->output->addWikiTextInterface( $text );
$this->startForm();
$this->endForm( false );
}
/**
* @param string $text
+ * @deprecated since 1.32; use addWikiTextInterface instead
*/
public function addWikiText( $text ) {
+ wfDeprecated( __METHOD__, '1.32' );
+ $this->addWikiTextInterface( $text );
+ }
+
+ /**
+ * @param string $text
+ */
+ public function addWikiTextInterface( $text ) {
$this->addHTML( $this->parent->parse( $text ) );
}
return 'continue';
}
}
- $this->parent->output->addWikiText( wfMessage( 'config-welcome' )->plain() );
+ $this->parent->output->addWikiTextInterface( wfMessage( 'config-welcome' )->plain() );
$status = $this->parent->doEnvironmentChecks();
if ( $status->isGood() ) {
$this->parent->output->addHTML( '<span class="success-message">' .
wfMessage( 'config-env-good' )->escaped() . '</span>' );
- $this->parent->output->addWikiText( wfMessage( 'config-copyright',
+ $this->parent->output->addWikiTextInterface( wfMessage( 'config-copyright',
SpecialVersion::getCopyrightAndAuthorList() )->plain() );
$this->startForm();
$this->endForm();
* Global state and $wgRequest are evil, but we're using it right
* now and sometimes we need to be able to force ResourceLoader to
* re-evaluate the context because it has changed (e.g. in the test suite).
+ *
+ * @internal For use by unit tests
+ * @codeCoverageIgnore
*/
public static function clearCache() {
self::$debugMode = null;
"confirm-unwatch-top": "Remove this page from your watchlist?",
"confirm-rollback-button": "OK",
"confirm-rollback-top": "Revert edits to this page?",
+ "confirm-mcrrestore-title": "Restore a revision",
"confirm-mcrundo-title": "Undo a change",
"mcrundofailed": "Undo failed",
"mcrundo-missingparam": "Missing required parameters on request.",
"confirm-unwatch-top": "Used as confirmation message.",
"confirm-rollback-button": "Used as Submit button text.\n{{Identical|OK}}",
"confirm-rollback-top": "Used as confirmation message.",
+ "confirm-mcrrestore-title": "Title for the editless restore form.",
"confirm-mcrundo-title": "Title for the editless undo form.",
"mcrundofailed": "Title of the error page when an editless undo fails.",
"mcrundo-missingparam": "Error displayed when parameters for action=mcrundo are missing",
--- /dev/null
+<?php
+
+/**
+ * Removes all users from a given user group.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+use MediaWiki\MediaWikiServices;
+
+class EmptyUserGroup extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Remove all users from a given user group' );
+ $this->addArg( 'group', 'Group to be removed', true );
+ }
+
+ public function execute() {
+ $group = $this->getArg( 0 );
+
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
+ $users = User::findUsersByGroup( $group );
+
+ $count = iterator_count( $users );
+
+ $this->output( "Removing $count users from $group..." );
+
+ /**
+ * @var User $user
+ */
+ foreach ( $users as $user ) {
+ $user->removeGroup( $group );
+
+ $lb->waitForReplication();
+ }
+
+ $this->output( " Done!\n" );
+ }
+}
+
+$maintClass = EmptyUserGroup::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
false,
true
);
- $this->addOption( 'tidy', 'Tidy the output' );
+ $this->addOption( 'no-tidy', 'Don\'t tidy the output (deprecated)' );
$this->addArg( 'file', 'File containing wikitext (Default: stdin)', false );
}
* @return string HTML Rendering
*/
public function render( $wikitext ) {
- return $this->parse( $wikitext )->getText();
+ return $this->parse( $wikitext )->getText( [ 'wrapperDivClass' => '' ] );
}
/**
* @return ParserOutput
*/
protected function parse( $wikitext ) {
- $options = new ParserOptions;
- if ( $this->getOption( 'tidy' ) ) {
- $options->setTidy( true );
+ $options = ParserOptions::newCanonical();
+ $options->setOption( 'enableLimitReport', false );
+ if ( $this->getOption( 'no-tidy' ) ) {
+ $options->setTidy( false );
}
return $this->parser->parse(
$wikitext,
qunit.css:
src: https://code.jquery.com/qunit/qunit-2.6.2.css
integrity: sha256-qpkurjTvVTJJCSpMABcvF4IlYUJkd8saxiHgUQpEjX8=
+
+sinonjs:
+ type: file
+ src: https://sinonjs.org/releases/sinon-1.17.3.js
+ integrity: sha384-8+RlaM2FW7qMqjxpM5NTVM0y6sTY+vTi/AHnk7Fd7NHjBye9sVxxsMjyxVJnPBtU
+ dest: sinon-1.17.3.js
} ).done( function ( data, jqXHR ) {
response( data[ 1 ], {
type: jqXHR.getResponseHeader( 'X-OpenSearch-Type' ),
+ searchId: jqXHR.getResponseHeader( 'X-Search-ID' ),
query: query
} );
} );
action: 'impression-results',
numberOfResults: context.config.suggestions.length,
resultSetType: metadata.type || 'unknown',
+ searchId: metadata.searchId || null,
query: metadata.query,
inputLocation: getInputLocation( context )
} );
// tracking purposes
promise.done( function ( data, jqXHR ) {
self.requestType = jqXHR.getResponseHeader( 'X-OpenSearch-Type' );
+ self.searchId = jqXHR.getResponseHeader( 'X-Search-ID' );
} );
return promise;
data: response || {},
metadata: {
type: this.requestType || 'unknown',
+ searchId: this.searchId || null,
query: this.getQueryValue()
}
};
this.requestType = undefined;
+ this.searchId = undefined;
return resp;
};
action: 'impression-results',
numberOfResults: items.length,
resultSetType: data.metadata.type,
+ searchId: data.metadata.searchId,
query: data.metadata.query,
inputLocation: this.dataLocation || 'header'
} );
}
}
+ // Re-enable any disabled deprecation warnings
+ MWDebug::clearLog();
// Restore mw globals
foreach ( $this->mwGlobals as $key => $value ) {
$GLOBALS[$key] = $value;
const SCREEN_MEDIA_QUERY = 'screen and (min-width: 982px)';
const SCREEN_ONLY_MEDIA_QUERY = 'only screen and (min-width: 982px)';
+ // Ensure that we don't affect the global ResourceLoader state.
+ protected function setUp() {
+ parent::setUp();
+ ResourceLoader::clearCache();
+ }
+ protected function tearDown() {
+ parent::tearDown();
+ ResourceLoader::clearCache();
+ }
+
/**
* @dataProvider provideRedirect
*
/**
* Test the actual behavior of the method (in the case where it doesn't throw, e.g., in
- * production). Since it threw an exception once in this file, it won't when we call it again.
+ * production).
*
* @covers OutputPage::addScriptFile
*/
public function testAddDeprecatedScriptFileNoOp() {
+ $this->hideDeprecated( 'OutputPage::addScriptFile' );
$op = $this->newInstance();
$op->addScriptFile( 'ignored-script.js' );
* @param array $expect
*/
public function testGetMessageFromException_BC( $exception, $options, $expect ) {
+ if ( $exception instanceof UsageException ) {
+ $this->hideDeprecated( 'UsageException::getMessageArray' );
+ }
+
$result = new ApiResult( 8388608 );
$formatter = new ApiErrorFormatter_BackCompat( $result );
$this->assertCount( 1, $res[0] );
} else {
$this->assertCount( 2, $res[0] );
- // This deliberately fails if there are extra warnings
- $this->assertSame( [ 'parse' => [ 'warnings' => $warnings ] ], $res[0]['warnings'] );
+ $this->assertSame( [ 'warnings' => $warnings ], $res[0]['warnings']['parse'] );
}
}
'disabletidy' => '',
] );
- $this->assertParsedTo( "<p><b>Mixed <i>up</b></i>\n</p>", $res2 );
+ $this->assertParsedTo( "<p><b>Mixed <i>up</b></i>\n</p>", $res2,
+ 'The parameter "disabletidy" has been deprecated.' );
}
public function testFormatCategories() {
$this->setMwGlobals( 'wgDevelopmentWarnings', false );
}
- public function tearDown() {
- parent::tearDown();
- MWDebug::clearLog();
- }
-
/**
* @dataProvider provideGet
*/