Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
9.80% |
30 / 306 |
|
6.67% |
1 / 15 |
CRAP | |
0.00% |
0 / 1 |
SpecialMassMessage | |
9.80% |
30 / 306 |
|
6.67% |
1 / 15 |
1598.67 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
doesWrites | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
alterForm | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
getDisplayFormat | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onSuccess | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getState | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getStatus | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCount | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getFormFields | |
0.00% |
0 / 99 |
|
0.00% |
0 / 1 |
20 | |||
onSubmit | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
getUnclosedTags | |
96.00% |
24 / 25 |
|
0.00% |
0 / 1 |
11 | |||
preview | |
0.00% |
0 / 103 |
|
0.00% |
0 / 1 |
72 | |||
showPreviewInfo | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
12 | |||
getLabeledSections | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace MediaWiki\MassMessage\Specials; |
4 | |
5 | use MediaWiki\Content\ContentHandler; |
6 | use MediaWiki\Content\TextContent; |
7 | use MediaWiki\EditPage\EditPage; |
8 | use MediaWiki\Html\Html; |
9 | use MediaWiki\HTMLForm\HTMLForm; |
10 | use MediaWiki\MassMessage\Lookup\SpamlistLookup; |
11 | use MediaWiki\MassMessage\MassMessage; |
12 | use MediaWiki\MassMessage\MessageBuilder; |
13 | use MediaWiki\MassMessage\MessageContentFetcher\LabeledSectionContentFetcher; |
14 | use MediaWiki\MassMessage\MessageContentFetcher\LocalMessageContentFetcher; |
15 | use MediaWiki\MassMessage\PageMessage\PageMessageBuilder; |
16 | use MediaWiki\MassMessage\RequestProcessing\MassMessageRequest; |
17 | use MediaWiki\MassMessage\RequestProcessing\MassMessageRequestParser; |
18 | use MediaWiki\MediaWikiServices; |
19 | use MediaWiki\Message\Message; |
20 | use MediaWiki\Parser\ParserOutputLinkTypes; |
21 | use MediaWiki\Parser\Parsoid\LintErrorChecker; |
22 | use MediaWiki\SpecialPage\FormSpecialPage; |
23 | use MediaWiki\Status\Status; |
24 | use MediaWiki\Title\Title; |
25 | use MediaWiki\WikiMap\WikiMap; |
26 | use OOUI\FieldsetLayout; |
27 | use OOUI\HtmlSnippet; |
28 | use OOUI\PanelLayout; |
29 | use OOUI\Widget; |
30 | |
31 | /** |
32 | * Form to allow users to send messages to a lot of users at once. |
33 | * |
34 | * @author Kunal Mehta |
35 | * @license GPL-2.0-or-later |
36 | */ |
37 | |
38 | class SpecialMassMessage extends FormSpecialPage { |
39 | /** @var Status */ |
40 | protected $status; |
41 | /** @var string */ |
42 | protected $state; |
43 | /** @var int */ |
44 | protected $count; |
45 | /** @var LocalMessageContentFetcher */ |
46 | private $localMessageContentFetcher; |
47 | /** @var LabeledSectionContentFetcher */ |
48 | private $labeledSectionContentFetcher; |
49 | /** @var MessageBuilder */ |
50 | private $messageBuilder; |
51 | /** @var PageMessageBuilder */ |
52 | private $pageMessageBuilder; |
53 | |
54 | private LintErrorChecker $lintErrorChecker; |
55 | |
56 | /** |
57 | * @param LabeledSectionContentFetcher $labeledSectionContentFetcher |
58 | * @param LocalMessageContentFetcher $localMessageContentFetcher |
59 | * @param PageMessageBuilder $pageMessageBuilder |
60 | * @param LintErrorChecker $lintErrorChecker |
61 | */ |
62 | public function __construct( |
63 | LabeledSectionContentFetcher $labeledSectionContentFetcher, |
64 | LocalMessageContentFetcher $localMessageContentFetcher, |
65 | PageMessageBuilder $pageMessageBuilder, |
66 | LintErrorChecker $lintErrorChecker |
67 | ) { |
68 | parent::__construct( 'MassMessage', 'massmessage' ); |
69 | $this->labeledSectionContentFetcher = $labeledSectionContentFetcher; |
70 | $this->localMessageContentFetcher = $localMessageContentFetcher; |
71 | $this->messageBuilder = new MessageBuilder(); |
72 | $this->pageMessageBuilder = $pageMessageBuilder; |
73 | $this->lintErrorChecker = $lintErrorChecker; |
74 | } |
75 | |
76 | public function doesWrites() { |
77 | return true; |
78 | } |
79 | |
80 | /** @inheritDoc */ |
81 | public function execute( $par ) { |
82 | $request = $this->getRequest(); |
83 | $output = $this->getOutput(); |
84 | |
85 | $this->addHelpLink( 'Help:Extension:MassMessage' ); |
86 | |
87 | $output->addModules( 'ext.MassMessage.special.js' ); |
88 | $output->addModuleStyles( 'ext.MassMessage.styles' ); |
89 | |
90 | // Some variables... |
91 | $this->status = new Status(); |
92 | |
93 | // Figure out what state we're in. |
94 | if ( $request->getCheck( 'submit-button' ) ) { |
95 | $this->state = 'submit'; |
96 | } elseif ( $request->getCheck( 'preview-button' ) ) { |
97 | $this->state = 'preview'; |
98 | } else { |
99 | $this->state = 'form'; |
100 | } |
101 | |
102 | parent::execute( $par ); |
103 | } |
104 | |
105 | /** @inheritDoc */ |
106 | protected function alterForm( HTMLForm $form ) { |
107 | if ( $this->state === 'form' ) { |
108 | $form->addPreHtml( $this->msg( 'massmessage-form-header' )->parse() ); |
109 | } |
110 | return $form |
111 | ->setId( 'mw-massmessage-form' ) |
112 | ->setWrapperLegendMsg( 'massmessage' ) |
113 | // We use our own buttons, so supress the default one. |
114 | ->suppressDefaultSubmit() |
115 | ->setMethod( 'post' ); |
116 | } |
117 | |
118 | /** @inheritDoc */ |
119 | protected function getDisplayFormat() { |
120 | return 'ooui'; |
121 | } |
122 | |
123 | /** @inheritDoc */ |
124 | public function onSuccess() { |
125 | if ( $this->state === 'submit' ) { |
126 | $output = $this->getOutput(); |
127 | $output->addWikiMsg( |
128 | 'massmessage-submitted', |
129 | Message::numParam( $this->count ) |
130 | ); |
131 | $output->addWikiMsg( 'massmessage-nextsteps' ); |
132 | } |
133 | } |
134 | |
135 | /** @return string */ |
136 | public function getState() { |
137 | return $this->state; |
138 | } |
139 | |
140 | /** @return Status */ |
141 | public function getStatus() { |
142 | return $this->status; |
143 | } |
144 | |
145 | /** |
146 | * Note that this won't be initalized unless submit is called. |
147 | * |
148 | * @return int |
149 | */ |
150 | public function getCount() { |
151 | return $this->count; |
152 | } |
153 | |
154 | /** @inheritDoc */ |
155 | protected function getFormFields() { |
156 | $request = $this->getRequest(); |
157 | $controlTabIndex = 1; |
158 | |
159 | $isPreview = $this->state === 'preview'; |
160 | |
161 | $m = []; |
162 | // Who to send to |
163 | $m['spamlist'] = [ |
164 | 'id' => 'mw-massmessage-form-spamlist', |
165 | 'name' => 'spamlist', |
166 | 'type' => 'title', |
167 | 'tabindex' => $controlTabIndex++, |
168 | 'label-message' => 'massmessage-form-spamlist', |
169 | 'default' => $request->getText( 'spamlist' ) |
170 | ]; |
171 | // The subject line |
172 | $m['subject'] = [ |
173 | 'id' => 'mw-massmessage-form-subject', |
174 | 'name' => 'subject', |
175 | 'type' => 'text', |
176 | 'tabindex' => $controlTabIndex++, |
177 | 'label-message' => 'massmessage-form-subject', |
178 | 'default' => $request->getText( 'subject' ), |
179 | 'help-message' => 'massmessage-form-subject-help', |
180 | 'maxlength' => 240 |
181 | ]; |
182 | |
183 | // The page to sent as message |
184 | $m['page-message'] = [ |
185 | 'id' => 'mw-massmessage-form-page', |
186 | 'name' => 'page-message', |
187 | 'type' => 'title', |
188 | 'tabindex' => $controlTabIndex++, |
189 | 'label-message' => 'massmessage-form-page', |
190 | 'default' => $request->getText( 'page-message' ), |
191 | 'help-message' => 'massmessage-form-page-help', |
192 | 'required' => false |
193 | ]; |
194 | |
195 | $options = [ '----' => '' ]; |
196 | $pagename = $request->getText( 'page-message' ); |
197 | if ( trim( $pagename ) !== '' ) { |
198 | $sections = $this->getLabeledSections( $pagename ); |
199 | $options += array_combine( $sections, $sections ); |
200 | } |
201 | |
202 | $m['page-subject-section'] = [ |
203 | 'id' => 'mw-massmessage-form-page-subject-section', |
204 | 'name' => 'page-subject-section', |
205 | 'type' => 'select', |
206 | 'options' => $options, |
207 | 'tabindex' => $controlTabIndex++, |
208 | 'disabled' => !$isPreview, |
209 | 'label-message' => 'massmessage-form-page-subject-section', |
210 | 'default' => $request->getText( 'page-subject-section' ), |
211 | 'help-message' => 'massmessage-form-page-subject-section-help', |
212 | ]; |
213 | |
214 | $m['page-message-section'] = [ |
215 | 'id' => 'mw-massmessage-form-page-section', |
216 | 'name' => 'page-message-section', |
217 | 'type' => 'select', |
218 | 'options' => $options, |
219 | 'tabindex' => $controlTabIndex++, |
220 | 'disabled' => !$isPreview, |
221 | 'label-message' => 'massmessage-form-page-message-section', |
222 | 'default' => $request->getText( 'page-message-section' ), |
223 | 'help-message' => 'massmessage-form-page-message-section-help', |
224 | ]; |
225 | |
226 | // The message to send |
227 | $m['message'] = [ |
228 | 'id' => 'mw-massmessage-form-message', |
229 | 'name' => 'message', |
230 | 'type' => 'textarea', |
231 | 'tabindex' => $controlTabIndex++, |
232 | 'label-message' => 'massmessage-form-message', |
233 | 'default' => $request->getText( 'message' ) |
234 | ]; |
235 | |
236 | // If we're previewing a message and there are no errors, show the copyright warning and |
237 | // the submit button. |
238 | if ( $isPreview ) { |
239 | $requestParser = new MassMessageRequestParser(); |
240 | $data = [ |
241 | 'spamlist' => $request->getText( 'spamlist' ), |
242 | 'subject' => $request->getText( 'subject' ), |
243 | 'page-message' => $request->getText( 'page-message' ), |
244 | 'page-message-section' => $request->getText( 'page-message-section' ), |
245 | 'page-subject-section' => $request->getText( 'page-subject-section' ), |
246 | 'message' => $request->getText( 'message' ) |
247 | ]; |
248 | $status = $requestParser->parseRequest( $data, $this->getUser() ); |
249 | if ( $status->isOK() ) { |
250 | $m['message']['help'] = EditPage::getCopyrightWarning( |
251 | $this->getPageTitle( false ), |
252 | 'parse', |
253 | $this |
254 | ); |
255 | $m['submit-button'] = [ |
256 | 'id' => 'mw-massmessage-form-submit-button', |
257 | 'name' => 'submit-button', |
258 | 'type' => 'submit', |
259 | 'tabindex' => $controlTabIndex++, |
260 | 'default' => $this->msg( 'massmessage-form-submit' )->text() |
261 | ]; |
262 | } |
263 | } |
264 | |
265 | $m['preview-button'] = [ |
266 | 'id' => 'mw-massmessage-form-preview-button', |
267 | 'name' => 'preview-button', |
268 | 'type' => 'submit', |
269 | 'tabindex' => $controlTabIndex++, |
270 | 'default' => $this->msg( 'massmessage-form-preview' )->text() |
271 | ]; |
272 | |
273 | return $m; |
274 | } |
275 | |
276 | /** |
277 | * Callback function. |
278 | * Does some basic verification of data. |
279 | * Decides whether to show the preview screen or the submitted message. |
280 | * |
281 | * @inheritDoc |
282 | * @return Status|bool |
283 | */ |
284 | public function onSubmit( array $data ) { |
285 | $requestParser = new MassMessageRequestParser(); |
286 | $this->status = $requestParser->parseRequest( $data, $this->getUser() ); |
287 | |
288 | // Die on errors. |
289 | if ( !$this->status->isOK() ) { |
290 | $this->state = 'form'; |
291 | return $this->status; |
292 | } |
293 | |
294 | if ( $this->state === 'submit' ) { |
295 | $this->count = MassMessage::submit( $this->getUser(), $this->status->getValue() ); |
296 | return $this->status; |
297 | } else { |
298 | // $this->state can only be 'preview' here |
299 | $this->preview( $this->status->getValue() ); |
300 | |
301 | // Die on errors. |
302 | if ( !$this->status->isOK() ) { |
303 | $this->state = 'form'; |
304 | return $this->status; |
305 | } |
306 | |
307 | // No submission attempted |
308 | return false; |
309 | } |
310 | } |
311 | |
312 | /** |
313 | * Returns an array containing possibly unclosed HTML tags in $message. |
314 | * |
315 | * TODO: Use an HTML parser instead of regular expressions |
316 | * |
317 | * @param string $message |
318 | * @return string[] |
319 | */ |
320 | protected function getUnclosedTags( $message ) { |
321 | // For start tags, ignore ones that contain '/' (assume those are self-closing). |
322 | preg_match_all( '|\<([\w]+)[^/]*?>|', $message, $startTags ); |
323 | preg_match_all( '|\</([\w]+)|', $message, $endTags ); |
324 | |
325 | // Keep just the element names from the matched patterns. |
326 | $startTags = $startTags[1] ?? []; |
327 | $endTags = $endTags[1] ?? []; |
328 | |
329 | // Stop and return an empty array if there are no HTML tags. |
330 | if ( !$startTags && !$endTags ) { |
331 | return []; |
332 | } |
333 | |
334 | // Construct a set containing elements that do not need an end tag. |
335 | // List obtained from http://www.w3.org/TR/html-markup/syntax.html#syntax-elements |
336 | $voidElements = array_flip( [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', |
337 | 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' ] ); |
338 | |
339 | // Count start / end tags for each element, ignoring start tags of void elements. |
340 | $tags = []; |
341 | foreach ( $startTags as $tag ) { |
342 | if ( !isset( $voidElements[$tag] ) ) { |
343 | if ( !isset( $tags[$tag] ) ) { |
344 | $tags[$tag] = 1; |
345 | } else { |
346 | $tags[$tag]++; |
347 | } |
348 | } |
349 | } |
350 | foreach ( $endTags as $tag ) { |
351 | if ( !isset( $tags[$tag] ) ) { |
352 | $tags[$tag] = -1; |
353 | } else { |
354 | $tags[$tag]--; |
355 | } |
356 | } |
357 | |
358 | $results = []; |
359 | foreach ( $tags as $element => $num ) { |
360 | if ( $num > 0 ) { |
361 | $results[] = '<' . $element . '>'; |
362 | } elseif ( $num < 0 ) { |
363 | $results[] = '</' . $element . '>'; |
364 | } |
365 | } |
366 | return $results; |
367 | } |
368 | |
369 | /** |
370 | * A preview/confirmation screen. |
371 | * The preview generation code was hacked up from EditPage.php. |
372 | * |
373 | * @param MassMessageRequest $request |
374 | */ |
375 | protected function preview( MassMessageRequest $request ) { |
376 | $this->getOutput()->addWikiMsg( 'massmessage-just-preview' ); |
377 | |
378 | // Output the number of recipients |
379 | $targets = SpamlistLookup::getTargets( $request->getSpamList() ); |
380 | $infoMessages = [ |
381 | $this->msg( 'massmessage-preview-count' )->numParams( count( $targets ) )->parse() |
382 | ]; |
383 | |
384 | $pageMessage = null; |
385 | $pageSubject = null; |
386 | if ( $request->hasPageMessage() ) { |
387 | $pageTitle = $this->localMessageContentFetcher |
388 | ->getTitle( $request->getPageMessage() ) |
389 | ->getValue(); |
390 | |
391 | if ( MassMessage::isSourceTranslationPage( $pageTitle ) ) { |
392 | $infoMessages[] = $this->msg( 'massmessage-translate-page-info' )->parse(); |
393 | } |
394 | |
395 | $pageMessageBuilderResult = $this->pageMessageBuilder->getContent( |
396 | $pageTitle, |
397 | $request->getPageMessageSection(), |
398 | $request->getPageSubjectSection(), |
399 | WikiMap::getCurrentWikiId() |
400 | ); |
401 | |
402 | if ( $pageMessageBuilderResult->isOK() ) { |
403 | $pageMessage = $pageMessageBuilderResult->getPageMessage(); |
404 | $pageSubject = $pageMessageBuilderResult->getPageSubject(); |
405 | } |
406 | } |
407 | |
408 | $this->showPreviewInfo( $infoMessages ); |
409 | |
410 | $messageText = $this->messageBuilder->buildMessage( |
411 | $request->getMessage(), |
412 | $pageMessage, |
413 | // This forces language wrapping always. Good for clarity |
414 | null, |
415 | $request->getComment() |
416 | ); |
417 | |
418 | $subjectText = $this->messageBuilder->buildSubject( |
419 | $request->getSubject(), |
420 | $pageSubject, |
421 | // This forces language wrapping always. Good for clarity |
422 | null |
423 | ); |
424 | |
425 | // Use a mock target as the context for rendering the preview |
426 | $mockTarget = Title::makeTitle( NS_PROJECT, 'MassMessage:A page that should not exist' ); |
427 | $services = MediaWikiServices::getInstance(); |
428 | $wikipage = $services->getWikiPageFactory()->newFromTitle( $mockTarget ); |
429 | |
430 | // Convert into a content object |
431 | $content = ContentHandler::makeContent( $messageText, $mockTarget ); |
432 | // Parser stuff. Taken from EditPage::getPreviewText() |
433 | $parserOptions = $wikipage->makeParserOptions( $this->getContext() ); |
434 | $parserOptions->setIsPreview( true ); |
435 | $parserOptions->setIsSectionPreview( false ); |
436 | $content = $content->addSectionHeader( $subjectText ); |
437 | |
438 | // Hooks not being run: EditPageGetPreviewContent, EditPageGetPreviewText |
439 | $contentTransformer = $services->getContentTransformer(); |
440 | $content = $contentTransformer->preSaveTransform( |
441 | $content, |
442 | $mockTarget, |
443 | MassMessage::getMessengerUser(), |
444 | $parserOptions |
445 | ); |
446 | $contentRenderer = $services->getContentRenderer(); |
447 | $parserOutput = $contentRenderer->getParserOutput( $content, $mockTarget, null, $parserOptions ); |
448 | $previewLayout = new PanelLayout( [ |
449 | 'content' => new FieldsetLayout( [ |
450 | 'label' => $this->msg( 'massmessage-fieldset-preview' )->text(), |
451 | 'items' => [ |
452 | new Widget( [ |
453 | 'content' => new HtmlSnippet( |
454 | $parserOutput->runOutputPipeline( $parserOptions, [ 'enableSectionEditLinks' => false ] ) |
455 | ->getContentHolderText() |
456 | ), |
457 | ] ), |
458 | ], |
459 | ] ), |
460 | 'expanded' => false, |
461 | 'framed' => true, |
462 | 'padded' => true, |
463 | ] ); |
464 | $this->getOutput()->addHTML( $previewLayout ); |
465 | |
466 | $wikitextPreviewLayout = new PanelLayout( [ |
467 | 'content' => [ |
468 | new FieldsetLayout( [ |
469 | 'label' => $this->msg( 'massmessage-fieldset-wikitext-preview' )->text(), |
470 | 'items' => [ |
471 | new Widget( [ |
472 | 'content' => new HtmlSnippet( |
473 | // @phan-suppress-next-next-line SecurityCheck-DoubleEscaped |
474 | // Intentionally including escaped HTML tags in the output |
475 | Html::element( 'pre', [], "== {$subjectText} ==\n\n$messageText" ) |
476 | ), |
477 | ] ), |
478 | ], |
479 | ] ), |
480 | ], |
481 | 'expanded' => false, |
482 | 'framed' => true, |
483 | 'padded' => true, |
484 | ] ); |
485 | $this->getOutput()->addHTML( $wikitextPreviewLayout ); |
486 | |
487 | // Check if we have unescaped langlinks (T56846) |
488 | if ( $parserOutput->getLinkList( ParserOutputLinkTypes::LANGUAGE ) ) { |
489 | $this->status->fatal( 'massmessage-unescaped-langlinks' ); |
490 | } |
491 | |
492 | // Check for unclosed HTML tags (T56909) |
493 | // TODO: This probably redundant with the Linter error "missing-end-tag" |
494 | // and can be removed. |
495 | $unclosedTags = $this->getUnclosedTags( $request->getMessage() ); |
496 | if ( $unclosedTags ) { |
497 | $this->status->fatal( |
498 | $this->msg( 'massmessage-badhtml' ) |
499 | ->params( $this->getLanguage()->commaList( |
500 | array_map( 'htmlspecialchars', $unclosedTags ) |
501 | ) ) |
502 | ->numParams( count( $unclosedTags ) ) |
503 | ); |
504 | } |
505 | |
506 | /** @var TextContent $content */ |
507 | '@phan-var TextContent $content'; |
508 | // Check for no timestamp (T56848) |
509 | if ( !preg_match( MassMessage::getTimestampRegex(), $content->getText() ) ) { |
510 | $this->status->fatal( 'massmessage-no-timestamp' ); |
511 | } |
512 | |
513 | // Check for Linter errors (T358818) |
514 | $lintErrors = $this->lintErrorChecker->check( $request->getMessage() ); |
515 | foreach ( $lintErrors as $e ) { |
516 | $msg = $this->msg( "linterror-{$e['type']}" )->parse(); |
517 | $this->status->fatal( 'massmessage-linter-error', $msg ); |
518 | } |
519 | } |
520 | |
521 | /** |
522 | * @param array $infoMessages |
523 | */ |
524 | protected function showPreviewInfo( array $infoMessages ) { |
525 | $infoListHtml = $infoMessages[0]; |
526 | if ( count( $infoMessages ) > 1 ) { |
527 | $infoListHtml = '<ul>'; |
528 | foreach ( $infoMessages as $info ) { |
529 | $infoListHtml .= '<li>' . $info . '</li>'; |
530 | } |
531 | $infoListHtml .= '</ul>'; |
532 | } |
533 | |
534 | $infoLayout = new PanelLayout( [ |
535 | 'content' => new FieldsetLayout( [ |
536 | 'label' => $this->msg( 'massmessage-fieldset-info' )->text(), |
537 | 'items' => [ |
538 | new Widget( [ |
539 | 'content' => new HtmlSnippet( $infoListHtml ) |
540 | ] ), |
541 | ], |
542 | ] ), |
543 | 'expanded' => false, |
544 | 'framed' => true, |
545 | 'padded' => true, |
546 | ] ); |
547 | |
548 | $this->getOutput()->addHTML( $infoLayout ); |
549 | } |
550 | |
551 | /** |
552 | * Get sections given a page name. |
553 | * |
554 | * @param string $pagename |
555 | * @return string[] |
556 | */ |
557 | private function getLabeledSections( string $pagename ): array { |
558 | $pageTitle = Title::newFromText( $pagename ); |
559 | if ( $pageTitle ) { |
560 | $status = $this->localMessageContentFetcher->getContent( $pageTitle ); |
561 | if ( $status->isOK() ) { |
562 | return $this->labeledSectionContentFetcher->getSections( |
563 | $status->getValue()->getWikitext() |
564 | ); |
565 | } |
566 | } |
567 | |
568 | return []; |
569 | } |
570 | } |