wikimedia/mediawiki-core

View on GitHub
includes/specials/SpecialRestSandbox.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
/**
 * 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
 */

namespace MediaWiki\Specials;

use MediaWiki\Html\Html;
use MediaWiki\HTMLForm\HTMLForm;
use MediaWiki\MainConfigNames;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Utils\UrlUtils;

/**
 * A special page showing a Swagger UI for exploring REST APIs.
 *
 * @ingroup SpecialPage
 * @since 1.43
 */
class SpecialRestSandbox extends SpecialPage {

    private UrlUtils $urlUtils;

    public function __construct( UrlUtils $urlUtils ) {
        parent::__construct( 'RestSandbox' );

        $this->urlUtils = $urlUtils;
    }

    /**
     * Returns the available choices for APIs to explore.
     *
     * @see MainConfigSchema::RestSandboxSpecs for the structure of the array
     *
     * @return array[]
     */
    private function getApiSpecs(): array {
        return $this->getConfig()->get( MainConfigNames::RestSandboxSpecs );
    }

    public function isListed() {
        // Hide the special pages if there are no APIs to explore.
        return $this->getApiSpecs() !== [];
    }

    protected function getGroupName() {
        return 'wiki';
    }

    private function getSpecUrl( ?string $apiId ): ?string {
        $apiSpecs = $this->getApiSpecs();

        if ( $apiId !== null && $apiId !== '' ) {
            $spec = $apiSpecs[$apiId] ?? null;
        } else {
            $spec = reset( $apiSpecs ) ?: null;
        }

        if ( !$spec ) {
            return null;
        }

        return $this->urlUtils->expand( $spec['url'] );
    }

    public function execute( $sub ) {
        $this->setHeaders();
        $out = $this->getOutput();
        $this->addHelpLink( 'Help:RestSandbox' );

        $apiId = $this->getRequest()->getText( 'api', $sub ?? '' );
        $specUrl = $this->getSpecUrl( $apiId );

        $apiSpecs = $this->getApiSpecs();

        $out->addJsConfigVars( [
            'specUrl' => $specUrl
        ] );

        $out->addModuleStyles( [
            'mediawiki.special',
            'mediawiki.hlist',
            'mediawiki.special.restsandbox.styles'
        ] );

        if ( !$apiSpecs ) {
            $out->addHTML( Html::errorBox(
                $out->msg( 'restsandbox-no-specs-configured' )->parse()
            ) );
            return;
        }

        $this->showForm( $apiSpecs );

        if ( !$specUrl ) {
            $out->addHTML( Html::errorBox(
                $out->msg( 'restsandbox-no-such-api' )->params( $apiId )->parse()
            ) );
            return;
        }

        $out->addModules( [
            'mediawiki.special.restsandbox'
        ] );

        $out->addHTML( Html::openElement( 'div', [ 'id' => 'mw-restsandbox' ] ) );

        // Hidden when JS is available
        $out->wrapWikiMsg(
            Html::element(
                'div',
                [ 'class' => [ 'mw-restsandbox-client-nojs', 'error', ], ],
                "\n$1\n"
            ),
            'restsandbox-jsonly'
        );

        // To be replaced by Swagger UI.
        $out->addElement( 'div', [ 'id' => 'mw-restsandbox-swagger-ui' ] );

        $out->addHTML( Html::closeElement( 'div' ) ); // #mw-restsandbox
    }

    private function showForm( array $apiSpecs ) {
        $apis = [];

        foreach ( $apiSpecs as $key => $spec ) {
            if ( isset( $spec['msg'] ) ) {
                $text = $this->msg( $spec['msg'] )->plain();
            } elseif ( isset( $spec['name'] ) ) {
                $text = $spec['name'];
            } else {
                $text = $key;
            }

            $apis[$text] = $key;
        }

        $formDescriptor = [
            'intro' => [
                'type' => 'info',
                'raw' => true,
                'default' => $this->msg( 'restsandbox-text' )->parseAsBlock()
            ],
            'api' => [
                'type' => 'select',
                'name' => 'api',
                'label-message' => 'restsandbox-select-api',
                'options' => $apis
            ],
            'title' => [
                'type' => 'hidden',
                'name' => 'title',
                'default' => $this->getPageTitle()->getPrefixedDBkey()
            ],
        ];

        $action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] );

        $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
        $htmlForm->setAction( $action );
        $htmlForm->setMethod( 'GET' );
        $htmlForm->setId( 'mw-restsandbox-form' );
        $htmlForm->prepareForm()->displayForm( false );
    }
}