Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
84.09% |
74 / 88 |
|
28.57% |
2 / 7 |
CRAP | |
0.00% |
0 / 1 |
SpecialRestSandbox | |
84.09% |
74 / 88 |
|
28.57% |
2 / 7 |
18.16 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getApiSpecs | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isListed | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSpecUrl | |
71.43% |
5 / 7 |
|
0.00% |
0 / 1 |
5.58 | |||
execute | |
81.82% |
36 / 44 |
|
0.00% |
0 / 1 |
4.10 | |||
showForm | |
93.75% |
30 / 32 |
|
0.00% |
0 / 1 |
4.00 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Specials; |
22 | |
23 | use MediaWiki\Html\Html; |
24 | use MediaWiki\HTMLForm\HTMLForm; |
25 | use MediaWiki\MainConfigNames; |
26 | use MediaWiki\SpecialPage\SpecialPage; |
27 | use MediaWiki\Utils\UrlUtils; |
28 | |
29 | /** |
30 | * A special page showing a Swagger UI for exploring REST APIs. |
31 | * |
32 | * @ingroup SpecialPage |
33 | * @since 1.43 |
34 | */ |
35 | class SpecialRestSandbox extends SpecialPage { |
36 | |
37 | private UrlUtils $urlUtils; |
38 | |
39 | public function __construct( UrlUtils $urlUtils ) { |
40 | parent::__construct( 'RestSandbox' ); |
41 | |
42 | $this->urlUtils = $urlUtils; |
43 | } |
44 | |
45 | /** |
46 | * Returns the available choices for APIs to explore. |
47 | * |
48 | * @see MainConfigSchema::RestSandboxSpecs for the structure of the array |
49 | * |
50 | * @return array[] |
51 | */ |
52 | private function getApiSpecs(): array { |
53 | return $this->getConfig()->get( MainConfigNames::RestSandboxSpecs ); |
54 | } |
55 | |
56 | public function isListed() { |
57 | // Hide the special pages if there are no APIs to explore. |
58 | return $this->getApiSpecs() !== []; |
59 | } |
60 | |
61 | protected function getGroupName() { |
62 | return 'wiki'; |
63 | } |
64 | |
65 | private function getSpecUrl( ?string $apiId ): ?string { |
66 | $apiSpecs = $this->getApiSpecs(); |
67 | |
68 | if ( $apiId !== null && $apiId !== '' ) { |
69 | $spec = $apiSpecs[$apiId] ?? null; |
70 | } else { |
71 | $spec = reset( $apiSpecs ) ?: null; |
72 | } |
73 | |
74 | if ( !$spec ) { |
75 | return null; |
76 | } |
77 | |
78 | return $this->urlUtils->expand( $spec['url'] ); |
79 | } |
80 | |
81 | public function execute( $sub ) { |
82 | $this->setHeaders(); |
83 | $out = $this->getOutput(); |
84 | $this->addHelpLink( 'Help:RestSandbox' ); |
85 | |
86 | $apiId = $this->getRequest()->getText( 'api', $sub ?? '' ); |
87 | $specUrl = $this->getSpecUrl( $apiId ); |
88 | |
89 | $apiSpecs = $this->getApiSpecs(); |
90 | |
91 | $out->addJsConfigVars( [ |
92 | 'specUrl' => $specUrl |
93 | ] ); |
94 | |
95 | $out->addModuleStyles( [ |
96 | 'mediawiki.special', |
97 | 'mediawiki.hlist', |
98 | 'mediawiki.special.restsandbox.styles' |
99 | ] ); |
100 | |
101 | if ( !$apiSpecs ) { |
102 | $out->addHTML( Html::errorBox( |
103 | $out->msg( 'restsandbox-no-specs-configured' )->parse() |
104 | ) ); |
105 | return; |
106 | } |
107 | |
108 | if ( $out->getLanguage()->getCode() !== 'en' ) { |
109 | $out->addHTML( Html::noticeBox( $out->msg( 'restsandbox-disclaimer' )->parse(), '' ) ); |
110 | } |
111 | |
112 | $this->showForm( $apiSpecs ); |
113 | |
114 | if ( !$specUrl ) { |
115 | $out->addHTML( Html::errorBox( |
116 | $out->msg( 'restsandbox-no-such-api' )->params( $apiId )->parse() |
117 | ) ); |
118 | return; |
119 | } |
120 | |
121 | $out->addModules( [ |
122 | 'mediawiki.codex.messagebox.styles', |
123 | 'mediawiki.special.restsandbox' |
124 | ] ); |
125 | |
126 | $out->addHTML( Html::openElement( 'div', [ 'id' => 'mw-restsandbox' ] ) ); |
127 | |
128 | // Hidden when JS is available |
129 | $out->addHTML( Html::errorBox( |
130 | $out->msg( 'restsandbox-jsonly' )->parse(), |
131 | '', |
132 | 'mw-restsandbox-client-nojs' |
133 | ) ); |
134 | |
135 | // To be replaced by Swagger UI. |
136 | $out->addElement( 'div', [ |
137 | 'id' => 'mw-restsandbox-swagger-ui', |
138 | // Force direction to "LTR" with swagger-ui. |
139 | // Since the swagger content is not internationalized, the information is always in English. |
140 | // We have to force the direction to "LTR" to avoid the content (specifically json strings) |
141 | // from being mangled. |
142 | 'dir' => 'ltr', |
143 | 'lang' => 'en', |
144 | // For dark mode compatibility |
145 | 'class' => 'skin-invert' |
146 | ] ); |
147 | |
148 | $out->addHTML( Html::closeElement( 'div' ) ); // #mw-restsandbox |
149 | } |
150 | |
151 | private function showForm( array $apiSpecs ) { |
152 | $apis = []; |
153 | |
154 | foreach ( $apiSpecs as $key => $spec ) { |
155 | if ( isset( $spec['msg'] ) ) { |
156 | $text = $this->msg( $spec['msg'] )->plain(); |
157 | } elseif ( isset( $spec['name'] ) ) { |
158 | $text = $spec['name']; |
159 | } else { |
160 | $text = $key; |
161 | } |
162 | |
163 | $apis[$text] = $key; |
164 | } |
165 | |
166 | $formDescriptor = [ |
167 | 'intro' => [ |
168 | 'type' => 'info', |
169 | 'raw' => true, |
170 | 'default' => $this->msg( 'restsandbox-text' )->parseAsBlock() |
171 | ], |
172 | 'api' => [ |
173 | 'type' => 'select', |
174 | 'name' => 'api', |
175 | 'label-message' => 'restsandbox-select-api', |
176 | 'options' => $apis |
177 | ], |
178 | 'title' => [ |
179 | 'type' => 'hidden', |
180 | 'name' => 'title', |
181 | 'default' => $this->getPageTitle()->getPrefixedDBkey() |
182 | ], |
183 | ]; |
184 | |
185 | $action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ); |
186 | |
187 | $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); |
188 | $htmlForm->setAction( $action ); |
189 | $htmlForm->setMethod( 'GET' ); |
190 | $htmlForm->setId( 'mw-restsandbox-form' ); |
191 | $htmlForm->prepareForm()->displayForm( false ); |
192 | } |
193 | } |