Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 144 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
SpecialTemplateSandbox | |
0.00% |
0 / 144 |
|
0.00% |
0 / 7 |
1560 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 80 |
|
0.00% |
0 / 1 |
182 | |||
validatePageParam | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
30 | |||
validateRevidParam | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
validatePrefixParam | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
56 | |||
onSubmit | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
56 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\TemplateSandbox; |
4 | |
5 | use Content; |
6 | use HTMLForm; |
7 | use MediaWiki\Content\IContentHandlerFactory; |
8 | use MediaWiki\Content\Renderer\ContentRenderer; |
9 | use MediaWiki\EditPage\EditPage; |
10 | use MediaWiki\Html\Html; |
11 | use MediaWiki\Page\WikiPageFactory; |
12 | use MediaWiki\Parser\ParserOutput; |
13 | use MediaWiki\Revision\RevisionLookup; |
14 | use MediaWiki\Revision\RevisionRecord; |
15 | use MediaWiki\Revision\SlotRecord; |
16 | use MediaWiki\SpecialPage\SpecialPage; |
17 | use MediaWiki\Status\Status; |
18 | use MediaWiki\Title\Title; |
19 | |
20 | class SpecialTemplateSandbox extends SpecialPage { |
21 | private $prefixes = []; |
22 | |
23 | /** |
24 | * @var null|ParserOutput |
25 | */ |
26 | private $output = null; |
27 | |
28 | /** @var RevisionLookup */ |
29 | private $revisionLookup; |
30 | |
31 | /** @var IContentHandlerFactory */ |
32 | private $contentHandlerFactory; |
33 | |
34 | /** @var WikiPageFactory */ |
35 | private $wikiPageFactory; |
36 | |
37 | /** @var ContentRenderer */ |
38 | private $contentRenderer; |
39 | |
40 | /** |
41 | * @param RevisionLookup $revisionLookup |
42 | * @param IContentHandlerFactory $contentHandlerFactory |
43 | * @param WikiPageFactory $wikiPageFactory |
44 | * @param ContentRenderer $contentRenderer |
45 | */ |
46 | public function __construct( |
47 | RevisionLookup $revisionLookup, |
48 | IContentHandlerFactory $contentHandlerFactory, |
49 | WikiPageFactory $wikiPageFactory, |
50 | ContentRenderer $contentRenderer |
51 | ) { |
52 | parent::__construct( 'TemplateSandbox' ); |
53 | $this->revisionLookup = $revisionLookup; |
54 | $this->contentHandlerFactory = $contentHandlerFactory; |
55 | $this->wikiPageFactory = $wikiPageFactory; |
56 | $this->contentRenderer = $contentRenderer; |
57 | } |
58 | |
59 | protected function getGroupName() { |
60 | return 'wiki'; |
61 | } |
62 | |
63 | public function execute( $par ) { |
64 | $this->setHeaders(); |
65 | $this->addHelpLink( 'Help:Extension:TemplateSandbox' ); |
66 | $this->checkPermissions(); |
67 | |
68 | $request = $this->getRequest(); |
69 | |
70 | if ( $par !== null && !$request->getCheck( 'page' ) ) { |
71 | $request->setVal( 'page', $par ); |
72 | } |
73 | |
74 | $default_prefix = Title::makeTitle( NS_USER, |
75 | $this->getUser()->getName() . '/' . $this->msg( 'templatesandbox-suffix' )->plain() |
76 | )->getPrefixedText(); |
77 | |
78 | $form = HTMLForm::factory( 'ooui', [ |
79 | 'prefix' => [ |
80 | 'type' => 'text', |
81 | 'name' => 'prefix', |
82 | 'default' => $default_prefix, |
83 | 'label-message' => 'templatesandbox-prefix-label', |
84 | 'validation-callback' => [ $this, 'validatePrefixParam' ], |
85 | ], |
86 | |
87 | 'page' => [ |
88 | 'type' => 'text', |
89 | 'name' => 'page', |
90 | 'label-message' => 'templatesandbox-page-label', |
91 | 'validation-callback' => [ $this, 'validatePageParam' ], |
92 | ], |
93 | |
94 | 'revid' => [ |
95 | 'type' => 'int', |
96 | 'name' => 'revid', |
97 | 'label-message' => 'templatesandbox-revid-label', |
98 | 'validation-callback' => [ $this, 'validateRevidParam' ], |
99 | ], |
100 | |
101 | 'text' => [ |
102 | 'type' => 'textarea', |
103 | 'name' => 'text', |
104 | 'label-message' => 'templatesandbox-text-label', |
105 | 'useeditfont' => true, |
106 | 'rows' => 5, |
107 | ], |
108 | ], $this->getContext() ); |
109 | $form->setSubmitCallback( [ $this, 'onSubmit' ] ); |
110 | $form->setWrapperLegendMsg( 'templatesandbox-legend' ); |
111 | $form->addHeaderHtml( $this->msg( 'templatesandbox-text' )->parseAsBlock() ); |
112 | $form->setSubmitTextMsg( 'templatesandbox-submit' ); |
113 | |
114 | $form->prepareForm(); |
115 | if ( $request->getCheck( 'page' ) || $request->getCheck( 'revid' ) ) { |
116 | $form->displayForm( $form->tryAuthorizedSubmit() ); |
117 | } else { |
118 | $form->displayForm( false ); |
119 | } |
120 | |
121 | $user = $this->getUser(); |
122 | $output = $this->getOutput(); |
123 | $error = false; |
124 | if ( $this->getRequest()->wasPosted() ) { |
125 | if ( $user->isAnon() && !$user->isAllowed( 'edit' ) ) { |
126 | $error = 'templatesandbox-fail-post-anon'; |
127 | } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) { |
128 | $error = 'templatesandbox-fail-post'; |
129 | } |
130 | } |
131 | if ( $error !== false ) { |
132 | $output->addHTML( |
133 | Html::errorBox( |
134 | $output->msg( $error )->parse(), |
135 | '', |
136 | 'previewnote' |
137 | ) |
138 | ); |
139 | } elseif ( $this->output !== null ) { |
140 | // Anons have predictable edit tokens, only do the JS/CSS preview for logged-in users. |
141 | if ( $user->isAnon() ) { |
142 | $output->addHTML( |
143 | Html::warningBox( |
144 | $output->msg( 'templatesandbox-anon-limited-preview' )->parse(), |
145 | 'previewnote' |
146 | ) |
147 | ); |
148 | } else { |
149 | Logic::addSubpageHandlerToOutput( $this->prefixes, $output ); |
150 | } |
151 | $output->addParserOutput( $this->output ); |
152 | |
153 | $output->addHTML( Html::rawElement( |
154 | 'div', |
155 | [ 'class' => 'limitreport', 'style' => 'clear:both' ], |
156 | EditPage::getPreviewLimitReport( $this->output ) |
157 | ) ); |
158 | $output->addModules( 'mediawiki.collapseFooterLists' ); |
159 | |
160 | $titleText = $this->output->getTitleText(); |
161 | if ( strval( $titleText ) !== '' ) { |
162 | $output->setPageTitleMsg( $this->msg( 'templatesandbox-title-output', $titleText ) ); |
163 | } |
164 | } |
165 | } |
166 | |
167 | /** |
168 | * @param string|null $value |
169 | * @param array $allData |
170 | * @return bool|string |
171 | */ |
172 | public function validatePageParam( $value, $allData ) { |
173 | if ( $value === '' || $value === null ) { |
174 | return true; |
175 | } |
176 | $title = Title::newFromText( $value ); |
177 | if ( !$title instanceof Title ) { |
178 | return $this->msg( 'templatesandbox-invalid-title' )->parseAsBlock(); |
179 | } |
180 | if ( !$title->exists() ) { |
181 | return $this->msg( 'templatesandbox-title-not-exists' )->parseAsBlock(); |
182 | } |
183 | return true; |
184 | } |
185 | |
186 | /** |
187 | * @param string|null $value |
188 | * @param array $allData |
189 | * @return bool|string |
190 | */ |
191 | public function validateRevidParam( $value, $allData ) { |
192 | if ( $value === '' || $value === null ) { |
193 | return true; |
194 | } |
195 | |
196 | $revisionRecord = $this->revisionLookup->getRevisionById( (int)$value ); |
197 | if ( $revisionRecord === null ) { |
198 | return $this->msg( 'templatesandbox-revision-not-exists' )->parseAsBlock(); |
199 | } |
200 | |
201 | $content = $revisionRecord->getContent( |
202 | SlotRecord::MAIN, |
203 | RevisionRecord::FOR_THIS_USER, |
204 | $this->getUser() |
205 | ); |
206 | |
207 | if ( $content === null ) { |
208 | return $this->msg( 'templatesandbox-revision-no-content' )->parseAsBlock(); |
209 | } |
210 | return true; |
211 | } |
212 | |
213 | /** |
214 | * @param string|null $value |
215 | * @param array $allData |
216 | * @return bool|string |
217 | */ |
218 | public function validatePrefixParam( $value, $allData ) { |
219 | if ( $value === '' || $value === null ) { |
220 | return true; |
221 | } |
222 | $prefixes = array_map( 'trim', explode( '|', $value ) ); |
223 | foreach ( $prefixes as $prefix ) { |
224 | $title = Title::newFromText( rtrim( $prefix, '/' ) ); |
225 | if ( !$title instanceof Title || $title->getFragment() !== '' ) { |
226 | return $this->msg( 'templatesandbox-invalid-prefix' )->parseAsBlock(); |
227 | } |
228 | if ( $title->isExternal() ) { |
229 | return $this->msg( 'templatesandbox-prefix-not-local' )->parseAsBlock(); |
230 | } |
231 | $this->prefixes[] = $title->getPrefixedText(); |
232 | } |
233 | return true; |
234 | } |
235 | |
236 | /** |
237 | * @param array $data |
238 | * @param HTMLForm $form |
239 | * @return Status |
240 | */ |
241 | public function onSubmit( $data, $form ) { |
242 | if ( $data['revid'] !== '' && $data['revid'] !== null ) { |
243 | $rev = $this->revisionLookup->getRevisionById( $data['revid'] ); |
244 | $title = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() ); |
245 | } elseif ( $data['page'] !== '' && $data['page'] !== null ) { |
246 | $title = Title::newFromText( $data['page'] ); |
247 | $rev = $this->revisionLookup->getRevisionByTitle( $title ); |
248 | } else { |
249 | return Status::newFatal( 'templatesandbox-page-or-revid' ); |
250 | } |
251 | |
252 | if ( $data['text'] !== '' && $data['text'] !== null ) { |
253 | $content = $this->contentHandlerFactory |
254 | ->getContentHandler( $rev->getSlot( SlotRecord::MAIN )->getModel() ) |
255 | ->unserializeContent( $data['text'] ); |
256 | } else { |
257 | $content = $rev->getContent( |
258 | SlotRecord::MAIN, |
259 | RevisionRecord::FOR_THIS_USER, |
260 | $this->getUser() |
261 | ); |
262 | } |
263 | |
264 | // Title and Content are validated by validatePrefixParam and validatePageParam |
265 | '@phan-var Title $title'; |
266 | '@phan-var Content $content'; |
267 | |
268 | $page = $this->wikiPageFactory->newFromTitle( $title ); |
269 | $popts = $page->makeParserOptions( $this->getContext() ); |
270 | $popts->setIsPreview( true ); |
271 | $popts->setIsSectionPreview( false ); |
272 | $logic = new Logic( $this->prefixes, null, null ); |
273 | $reset = $logic->setupForParse( $popts ); |
274 | $this->output = $this->contentRenderer->getParserOutput( $content, $title, $rev, $popts ); |
275 | |
276 | return Status::newGood(); |
277 | } |
278 | } |