83 $this->config = $config;
84 $this->linkRenderer = $linkRenderer;
85 $this->permManager = $permManager;
86 $this->userNameUtils = $userNameUtils;
87 $this->tempUserCreator = $tempUserCreator;
88 $this->userFactory = $userFactory;
89 $this->restrictionStore = $restrictionStore;
90 $this->blockStore = $blockStore;
91 $this->readOnlyMode = $readOnlyMode;
92 $this->specialPageFactory = $specialPageFactory;
93 $this->repoGroup = $repoGroup;
94 $this->namespaceInfo = $namespaceInfo;
95 $this->skinFactory = $skinFactory;
96 $this->dbProvider = $dbProvider;
97 $this->urlUtils = $urlUtils;
112 private function getLogExtract( $types = [], $page =
'', $user =
'', $param = [] ): string {
114 LogEventsList::showLogExtract( $outString, $types, $page, $user, $param );
150 ?
string $returnToQuery,
152 ?
string $section =
null
154 $title =
Title::newFromPageIdentity( $page );
157 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
160 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
161 $this->addSharedRepoHint( $messages, $localizer, $page );
162 $this->addUserWarnings( $messages, $localizer, $title, $performer );
163 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
164 $this->addRecreateWarning( $messages, $localizer, $page );
167 $this->addTalkPageText( $messages, $localizer, $title );
168 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
170 $this->addReadOnlyWarning( $messages, $localizer );
171 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
172 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
173 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
174 $this->addHeaderCopyrightWarning( $messages, $localizer );
176 return $messages->getList();
182 private function addCodeEditingIntro(
183 IntroMessageList $messages,
188 $isUserJsConfig = $title->isUserJsConfigPage();
189 $namespace = $title->getNamespace();
193 $title->isUserConfigPage() &&
194 $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) )
196 $isUserCssConfig = $title->isUserCssConfigPage();
197 $isUserJsonConfig = $title->isUserJsonConfigPage();
198 $isUserJsConfig = $title->isUserJsConfigPage();
200 if ( $isUserCssConfig ) {
201 $warning =
'usercssispublic';
202 } elseif ( $isUserJsonConfig ) {
203 $warning =
'userjsonispublic';
205 $warning =
'userjsispublic';
208 $warningText = $localizer->
msg( $warning )->parse();
209 $intro .= $warningText ? Html::rawElement(
211 [
'class' =>
'mw-userconfigpublic' ],
216 $codeMsg = $localizer->
msg(
'editpage-code-message' );
217 $codeMessageText = $codeMsg->isDisabled() ?
'' : $codeMsg->parseAsBlock();
222 $interfaceMsg = $localizer->
msg(
'editinginterface' );
223 $interfaceMsgText = $interfaceMsg->parse();
224 # Show a warning if editing an interface message
225 $intro .= $interfaceMsgText ? Html::rawElement(
227 [
'class' =>
'mw-editinginterface' ],
230 # If this is a default message (but not css, json, or js),
231 # show a hint that it is translatable on translatewiki.net
237 $defaultMessageText = $title->getDefaultMessageText();
238 if ( $defaultMessageText !==
false ) {
239 $translateInterfaceText = $localizer->
msg(
'translateinterface' )->parse();
240 $intro .= $translateInterfaceText ? Html::rawElement(
242 [
'class' =>
'mw-translateinterface' ],
243 $translateInterfaceText
249 if ( $isUserJsConfig ) {
250 $userConfigDangerousMsg = $localizer->
msg(
'userjsdangerous' )->parse();
251 $intro .= $userConfigDangerousMsg ? Html::rawElement(
253 [
'class' =>
'mw-userconfigdangerous' ],
254 $userConfigDangerousMsg
259 if ( $isJavaScript || $isCSS ) {
260 $intro .= $codeMessageText;
263 $messages->addWithKey(
264 'code-editing-intro',
270 Html::errorBox(
'$1' )
274 private function addSharedRepoHint(
275 IntroMessageList $messages,
277 ProperPageIdentity $page
279 $namespace = $page->getNamespace();
280 if ( $namespace ===
NS_FILE ) {
281 # Show a hint to shared repo
282 $file = $this->repoGroup->findFile( $page );
283 if ( $file && !$file->isLocal() ) {
284 $descUrl = $file->getDescriptionUrl();
285 # there must be a description url to show a hint to shared repo
287 if ( !$page->exists() ) {
290 'sharedupload-desc-create',
291 $file->getRepo()->getDisplayName(),
294 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
299 'sharedupload-desc-edit',
300 $file->getRepo()->getDisplayName(),
303 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
311 private function addUserWarnings(
312 IntroMessageList $messages,
317 $namespace = $title->getNamespace();
318 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
319 # Show log extract when the user is currently blocked
321 $username = explode(
'/', $title->getText(), 2 )[0];
323 $validation = UserRigorOptions::RIGOR_NONE;
324 $user = $this->userFactory->newFromName( $username, $validation );
325 $ip = $this->userNameUtils->isIP( $username );
326 $block = $this->blockStore->newFromTarget( $user, $user );
328 $userExists = ( $user && $user->isRegistered() );
329 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
335 if ( !$userExists && !$ip ) {
336 $messages->addWithKey(
337 'userpage-userdoesnotexist',
341 'mw-userpage-userdoesnotexist'
346 $block->getType() !== Block::TYPE_AUTO &&
348 $block->isSitewide() ||
349 $this->permManager->isBlockedFrom(
359 $messages->addWithKey(
360 'blocked-notice-logextract',
361 $this->getLogExtract(
363 $this->namespaceInfo->getCanonicalName(
NS_USER ) .
':' . $block->getTargetName(),
367 'showIfEmpty' =>
false,
369 'blocked-notice-logextract',
370 $user->getName() # Support GENDER in notice
382 private function addEditIntro(
383 IntroMessageList $messages,
385 ProperPageIdentity $page,
386 Authority $performer,
390 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
392 $editIntro =
'MediaWiki:addsection-editintro';
394 if ( $editIntro !==
null && $editIntro !==
'' ) {
395 $introTitle = Title::newFromText( $editIntro );
399 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
401 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
402 $messages->addWithKey(
404 $localizer->
msg(
new RawMessage(
406 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
409 ->inContentLanguage()
416 if ( !$page->exists() ) {
417 $helpLink = $this->urlUtils->expand(
419 $localizer->
msg(
'helppage' )->inContentLanguage()->text()
423 if ( $helpLink ===
null ) {
424 throw new LogicException(
'Help link was invalid, this should be impossible' );
426 if ( $performer->getUser()->isRegistered() ) {
428 $localizer->
msg(
'newarticletext', $helpLink ),
430 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
434 $localizer->
msg(
'newarticletextanon', $helpLink ),
436 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
442 private function addRecreateWarning(
443 IntroMessageList $messages,
445 ProperPageIdentity $page
447 # Give a notice
if the user is editing a deleted/moved page...
448 if ( !$page->exists() ) {
449 $dbr = $this->dbProvider->getReplicaDatabase();
451 $messages->addWithKey(
452 'recreate-moveddeleted-warn',
453 $this->getLogExtract( [
'delete',
'move',
'merge' ], $page,
'', [
455 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
456 'showIfEmpty' =>
false,
457 'msgKey' => [
'recreate-moveddeleted-warn' ],
463 private function addTalkPageText(
464 IntroMessageList $messages,
468 if ( $title->isTalkPage() ) {
469 $messages->add( $localizer->
msg(
'talkpagetext' ) );
473 private function addEditNotices(
474 IntroMessageList $messages,
477 ?RevisionRecord $revRecord
479 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
480 if ( count( $editNotices ) ) {
481 foreach ( $editNotices as $key => $html ) {
482 $messages->addWithKey( $key, $html );
485 $msg = $localizer->
msg(
'editnotice-notext' );
486 if ( !$msg->isDisabled() ) {
487 $messages->addWithKey(
491 [
'class' =>
'mw-editnotice-notext' ],
499 private function addOldRevisionWarning(
500 IntroMessageList $messages,
502 ?RevisionRecord $revRecord
504 if ( $revRecord && !$revRecord->isCurrent() ) {
506 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->
msg(
'editingold' )->parse() ) );
510 private function addReadOnlyWarning(
511 IntroMessageList $messages,
514 if ( $this->readOnlyMode->isReadOnly() ) {
516 $localizer->
msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
517 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
522 private function addAnonEditWarning(
523 IntroMessageList $messages,
526 Authority $performer,
527 ?
string $returnToQuery,
530 if ( !$performer->
getUser()->isRegistered() ) {
531 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
533 $messages->addWithKey(
536 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
538 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
539 'returnto' => $title->getPrefixedDBkey(),
540 'returntoquery' => $returnToQuery,
543 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
544 'returnto' => $title->getPrefixedDBkey(),
545 'returntoquery' => $returnToQuery,
548 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
551 $messages->addWithKey(
553 $localizer->
msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
555 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
564 private function isWrongCaseUserConfigPage( Title $title ): bool {
565 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
566 $name = $title->getSkinFromConfigSubpage();
567 $skins = array_merge(
568 array_keys( $this->skinFactory->getInstalledSkins() ),
571 return !in_array( $name, $skins,
true )
572 && in_array( strtolower( $name ), $skins,
true );
578 private function addUserConfigPageInfo(
579 IntroMessageList $messages,
582 Authority $performer,
585 if ( $title->isUserConfigPage() ) {
586 # Check the skin exists
587 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
589 $localizer->
msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
590 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
593 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
594 $isUserCssConfig = $title->isUserCssConfigPage();
595 $isUserJsonConfig = $title->isUserJsonConfigPage();
596 $isUserJsConfig = $title->isUserJsConfigPage();
599 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
601 $localizer->
msg(
'usercssyoucanpreview' ),
602 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
604 } elseif ( $isUserJsonConfig ) {
606 $localizer->
msg(
'userjsonyoucanpreview' ),
607 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
609 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
611 $localizer->
msg(
'userjsyoucanpreview' ),
612 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
620 private function addPageProtectionWarningHeaders(
621 IntroMessageList $messages,
623 ProperPageIdentity $page
625 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
626 $this->permManager->getNamespaceRestrictionLevels(
627 $page->getNamespace()
630 # Is the title semi-protected?
631 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
632 $noticeMsg =
'semiprotectedpagewarning';
634 # Then it must be protected based on static groups (regular)
635 $noticeMsg =
'protectedpagewarning';
637 $messages->addWithKey(
639 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
642 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
643 # Is this page under cascading protection from some source pages?
644 $cascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[0];
646 # Explain, and list the titles responsible
647 foreach ( $cascadeSources as
$source ) {
648 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
650 $messages->addWithKey(
651 'cascadeprotectedwarning',
652 $localizer->
msg(
'cascadeprotectedwarning', count( $cascadeSources ) )->parse() .
653 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
654 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
657 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
658 $messages->addWithKey(
659 'titleprotectedwarning',
660 $this->getLogExtract(
665 'showIfEmpty' =>
false,
666 'msgKey' => [
'titleprotectedwarning' ],
667 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
674 private function addHeaderCopyrightWarning(
675 IntroMessageList $messages,
679 $localizer->msg(
'editpage-head-copy-warn' ),
680 "<div class='editpage-head-copywarn'>\n$1\n</div>"