diff --git a/ApiVisualEditor.php b/ApiVisualEditor.php index 4d5f4f1d3d..5ef8e19415 100644 --- a/ApiVisualEditor.php +++ b/ApiVisualEditor.php @@ -289,14 +289,8 @@ class ApiVisualEditor extends ApiBase { $isSafeAction = in_array( $params['paction'], self::$SAFE_ACTIONS, true ); - $availableNamespaces = $this->veConfig->get( 'VisualEditorAvailableNamespaces' ); - if ( !$isSafeAction && ( - !isset( $availableNamespaces[$title->getNamespace()] ) || - !$availableNamespaces[$title->getNamespace()] - ) ) { - - $this->dieUsage( "VisualEditor is not enabled in namespace " . - $title->getNamespace(), 'novenamespace' ); + if ( !$isSafeAction ) { + $this->checkAllowedNamespace( $title->getNamespace() ); } $parserParams = []; @@ -632,6 +626,34 @@ class ApiVisualEditor extends ApiBase { $this->getResult()->addValue( null, $this->getModuleName(), $result ); } + /** + * Check if the request is allowed to proceed in the current namespace, and abort if not + * + * @param int $namespaceId Namespace ID + */ + public function checkAllowedNamespace( $namespaceId ) { + if ( !self::isAllowedNamespace( $this->veConfig, $namespaceId ) ) { + $this->dieUsage( "VisualEditor is not enabled in '" . + MWNamespace::getCanonicalName( $namespaceId ) . "' namespace ", + 'novenamespace' ); + } + } + + /** + * Check if the configured allowed namespaces include the specified namespace + * + * @param Config $config Configuration object + * @param int $namespaceId Namespace ID + * @return boolean + */ + public static function isAllowedNamespace( Config $config, $namespaceId ) { + $availableNamespaces = $config->get( 'VisualEditorAvailableNamespaces' ); + $canonicalName = MWNamespace::getCanonicalName( $namespaceId ); + return ( isset( $availableNamespaces[$namespaceId] ) && $availableNamespaces[$namespaceId] ) || + ( isset( $availableNamespaces[$canonicalName] ) && $availableNamespaces[$canonicalName] ); + + } + /** * Gets the relevant HTML for the latest log entry on a given title, including a full log link. * diff --git a/ApiVisualEditorEdit.php b/ApiVisualEditorEdit.php index b334256e4b..8d315811c2 100644 --- a/ApiVisualEditorEdit.php +++ b/ApiVisualEditorEdit.php @@ -122,16 +122,12 @@ class ApiVisualEditorEdit extends ApiVisualEditor { public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); - $page = Title::newFromText( $params['page'] ); - if ( !$page ) { + $title = Title::newFromText( $params['page'] ); + if ( !$title ) { $this->dieUsageMsg( 'invalidtitle', $params['page'] ); } - $availableNamespaces = $this->veConfig->get( 'VisualEditorAvailableNamespaces' ); - if ( !isset( $availableNamespaces[$page->getNamespace()] ) || - !$availableNamespaces[$page->getNamespace()] ) { - $this->dieUsage( "VisualEditor is not enabled in namespace " . - $page->getNamespace(), 'novenamespace' ); - } + + $this->checkAllowedNamespace( $title->getNamespace() ); $parserParams = []; if ( isset( $params['oldid'] ) ) { @@ -149,13 +145,13 @@ class ApiVisualEditorEdit extends ApiVisualEditor { $this->dieUsage( 'No cached serialization found with that key', 'badcachekey' ); } } else { - $wikitext = $this->postHTML( $page, $html, $parserParams, $params['etag'] ); + $wikitext = $this->postHTML( $title, $html, $parserParams, $params['etag'] ); if ( $wikitext === false ) { $this->dieUsage( 'Error contacting the Parsoid/RESTbase server', 'docserver' ); } } - $saveresult = $this->saveWikitext( $page, $wikitext, $params ); + $saveresult = $this->saveWikitext( $title, $wikitext, $params ); $editStatus = $saveresult['edit']['result']; // Error @@ -184,17 +180,17 @@ class ApiVisualEditorEdit extends ApiVisualEditor { } ); } } else { - $newRevId = $page->getLatestRevId(); + $newRevId = $title->getLatestRevId(); } // Return result of parseWikitext instead of saveWikitext so that the // frontend can update the page rendering without a refresh. - $result = $this->parseWikitext( $page, $newRevId ); + $result = $this->parseWikitext( $title, $newRevId ); if ( $result === false ) { $this->dieUsage( 'Error contacting the Parsoid/RESTBase server', 'docserver' ); } - $result['isRedirect'] = $page->isRedirect(); + $result['isRedirect'] = $title->isRedirect(); if ( class_exists( 'FlaggablePageView' ) ) { $view = FlaggablePageView::singleton(); @@ -207,12 +203,12 @@ class ApiVisualEditorEdit extends ApiVisualEditor { [ 'diff' => null, 'oldid' => '', - 'title' => $page->getPrefixedText(), + 'title' => $title->getPrefixedText(), 'action' => 'view' ] + $this->getRequest()->getValues() ); $view->getContext()->setRequest( $newRequest ); - RequestContext::getMain()->setTitle( $page ); + RequestContext::getMain()->setTitle( $title ); // The two parameters here are references but we don't care // about what FlaggedRevs does with them. diff --git a/VisualEditor.hooks.php b/VisualEditor.hooks.php index 5dc3c0536e..47458ac6a0 100644 --- a/VisualEditor.hooks.php +++ b/VisualEditor.hooks.php @@ -125,8 +125,6 @@ class VisualEditorHooks { $title = $article->getTitle(); - $availableNamespaces = $veConfig->get( 'VisualEditorAvailableNamespaces' ); - $params = $req->getValues(); if ( isset( $params['venoscript'] ) ) { @@ -144,7 +142,7 @@ class VisualEditorHooks { !$veConfig->get( 'VisualEditorUseSingleEditTab' ) || self::getUserEditor( $user, $req ) === 'wikitext' || !$title->quickUserCan( 'edit' ) || - !$title->inNamespaces( array_keys( array_filter( $availableNamespaces ) ) ) || + !ApiVisualEditor::isAllowedNamespace( $veConfig, $title->getNamespace() ) || $title->getContentModel() !== CONTENT_MODEL_WIKITEXT || // Known parameters that VE does not handle // TODO: Other params too? See identical list in ve.init.mw.DesktopArticleTarget.init.js @@ -272,9 +270,8 @@ class VisualEditorHooks { return true; } - $availableNamespaces = $config->get( 'VisualEditorAvailableNamespaces' ); $title = $skin->getRelevantTitle(); - $namespaceEnabled = $title->inNamespaces( array_keys( array_filter( $availableNamespaces ) ) ); + $namespaceEnabled = ApiVisualEditor::isAllowedNamespace( $config, $title->getNamespace() ); $pageContentModel = $title->getContentModel(); // Don't exit if this page isn't VE-enabled, since we should still // change "Edit" to "Edit source". @@ -472,10 +469,8 @@ class VisualEditorHooks { $result['editsection']['text'] = $skin->msg( $sourceEditSection )->inLanguage( $lang )->text(); - $availableNamespaces = $config->get( 'VisualEditorAvailableNamespaces' ); - // add VE edit section in VE available namespaces - if ( $title->inNamespaces( array_keys( array_filter( $availableNamespaces ) ) ) ) { + if ( ApiVisualEditor::isAllowedNamespace( $config, $title->getNamespace() ) ) { $veEditSection = $tabMessages['editsection'] !== null ? $tabMessages['editsection'] : 'editsection'; $veLink = [ @@ -676,7 +671,12 @@ class VisualEditorHooks { $thumbLimits = $coreConfig->get( 'ThumbLimits' ); $veConfig = ConfigFactory::getDefaultInstance()->makeConfig( 'visualeditor' ); $availableNamespaces = $veConfig->get( 'VisualEditorAvailableNamespaces' ); - $enabledNamespaces = array_keys( array_filter( $availableNamespaces ) ); + $enabledNamespaces = array_map( function ( $namespace ) { + // Convert canonical namespace names to IDs + return is_numeric( $namespace ) ? + $namespace : + MWNamespace::getCanonicalIndex( strtolower( $namespace ) ); + }, array_keys( array_filter( $availableNamespaces ) ) ); $vars['wgVisualEditorConfig'] = [ 'disableForAnons' => $veConfig->get( 'VisualEditorDisableForAnons' ), diff --git a/extension.json b/extension.json index 02bf29b3c6..5bf508c941 100644 --- a/extension.json +++ b/extension.json @@ -98,7 +98,7 @@ "VisualEditorAutoAccountEnable": false, "VisualEditorTransitionDefault": false, "VisualEditorAvailableNamespaces": { - "2": true, + "User": true, "_merge_strategy": "array_plus" }, "VisualEditorSkinToolbarScrollOffset": [],