79 $this->config = $config;
80 $this->linkRenderer = $linkRenderer;
81 $this->permManager = $permManager;
82 $this->userNameUtils = $userNameUtils;
83 $this->tempUserCreator = $tempUserCreator;
84 $this->userFactory = $userFactory;
85 $this->restrictionStore = $restrictionStore;
86 $this->blockStore = $blockStore;
87 $this->readOnlyMode = $readOnlyMode;
88 $this->specialPageFactory = $specialPageFactory;
89 $this->repoGroup = $repoGroup;
90 $this->namespaceInfo = $namespaceInfo;
91 $this->skinFactory = $skinFactory;
92 $this->dbProvider = $dbProvider;
107 private function getLogExtract( $types = [], $page =
'', $user =
'', $param = [] ): string {
145 ?
string $returnToQuery,
147 ?
string $section =
null
149 $title =
Title::newFromPageIdentity( $page );
152 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
155 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
156 $this->addSharedRepoHint( $messages, $localizer, $page );
157 $this->addUserWarnings( $messages, $localizer, $title, $performer );
158 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
159 $this->addRecreateWarning( $messages, $localizer, $page );
162 $this->addTalkPageText( $messages, $localizer, $title );
163 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
165 $this->addReadOnlyWarning( $messages, $localizer );
166 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
167 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
168 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
169 $this->addHeaderCopyrightWarning( $messages, $localizer );
171 return $messages->getList();
177 private function addCodeEditingIntro(
178 IntroMessageList $messages,
183 $isUserJsConfig = $title->isUserJsConfigPage();
184 $namespace = $title->getNamespace();
188 $title->isUserConfigPage() &&
189 $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) )
191 $isUserCssConfig = $title->isUserCssConfigPage();
192 $isUserJsonConfig = $title->isUserJsonConfigPage();
193 $isUserJsConfig = $title->isUserJsConfigPage();
195 if ( $isUserCssConfig ) {
196 $warning =
'usercssispublic';
197 } elseif ( $isUserJsonConfig ) {
198 $warning =
'userjsonispublic';
200 $warning =
'userjsispublic';
203 $warningText = $localizer->
msg( $warning )->parse();
204 $intro .= $warningText ? Html::rawElement(
206 [
'class' =>
'mw-userconfigpublic' ],
211 $codeMsg = $localizer->
msg(
'editpage-code-message' );
212 $codeMessageText = $codeMsg->isDisabled() ?
'' : $codeMsg->parseAsBlock();
217 $interfaceMsg = $localizer->
msg(
'editinginterface' );
218 $interfaceMsgText = $interfaceMsg->parse();
219 # Show a warning if editing an interface message
220 $intro .= $interfaceMsgText ? Html::rawElement(
222 [
'class' =>
'mw-editinginterface' ],
225 # If this is a default message (but not css, json, or js),
226 # show a hint that it is translatable on translatewiki.net
232 $defaultMessageText = $title->getDefaultMessageText();
233 if ( $defaultMessageText !==
false ) {
234 $translateInterfaceText = $localizer->
msg(
'translateinterface' )->parse();
235 $intro .= $translateInterfaceText ? Html::rawElement(
237 [
'class' =>
'mw-translateinterface' ],
238 $translateInterfaceText
244 if ( $isUserJsConfig ) {
245 $userConfigDangerousMsg = $localizer->
msg(
'userjsdangerous' )->parse();
246 $intro .= $userConfigDangerousMsg ? Html::rawElement(
248 [
'class' =>
'mw-userconfigdangerous' ],
249 $userConfigDangerousMsg
254 if ( $isJavaScript || $isCSS ) {
255 $intro .= $codeMessageText;
258 $messages->addWithKey(
259 'code-editing-intro',
265 Html::errorBox(
'$1' )
269 private function addSharedRepoHint(
270 IntroMessageList $messages,
272 ProperPageIdentity $page
274 $namespace = $page->getNamespace();
275 if ( $namespace ===
NS_FILE ) {
276 # Show a hint to shared repo
277 $file = $this->repoGroup->findFile( $page );
278 if ( $file && !$file->isLocal() ) {
279 $descUrl = $file->getDescriptionUrl();
280 # there must be a description url to show a hint to shared repo
282 if ( !$page->exists() ) {
285 'sharedupload-desc-create',
286 $file->getRepo()->getDisplayName(),
289 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
294 'sharedupload-desc-edit',
295 $file->getRepo()->getDisplayName(),
298 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
306 private function addUserWarnings(
307 IntroMessageList $messages,
312 $namespace = $title->getNamespace();
313 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
314 # Show log extract when the user is currently blocked
316 $username = explode(
'/', $title->getText(), 2 )[0];
318 $validation = UserRigorOptions::RIGOR_NONE;
319 $user = $this->userFactory->newFromName( $username, $validation );
320 $ip = $this->userNameUtils->isIP( $username );
321 $block = $this->blockStore->newFromTarget( $user, $user );
323 $userExists = ( $user && $user->isRegistered() );
324 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
330 if ( !$userExists && !$ip ) {
331 $messages->addWithKey(
332 'userpage-userdoesnotexist',
336 'mw-userpage-userdoesnotexist'
341 $block->getType() !== Block::TYPE_AUTO &&
343 $block->isSitewide() ||
344 $this->permManager->isBlockedFrom(
354 $messages->addWithKey(
355 'blocked-notice-logextract',
356 $this->getLogExtract(
358 $this->namespaceInfo->getCanonicalName(
NS_USER ) .
':' . $block->getTargetName(),
362 'showIfEmpty' =>
false,
364 'blocked-notice-logextract',
365 $user->getName() # Support GENDER in notice
377 private function addEditIntro(
378 IntroMessageList $messages,
380 ProperPageIdentity $page,
381 Authority $performer,
385 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
387 $editIntro =
'MediaWiki:addsection-editintro';
389 if ( $editIntro !==
null && $editIntro !==
'' ) {
390 $introTitle = Title::newFromText( $editIntro );
394 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
396 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
397 $messages->addWithKey(
399 $localizer->
msg(
new RawMessage(
401 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
404 ->inContentLanguage()
411 if ( !$page->exists() ) {
413 $localizer->
msg(
'helppage' )->inContentLanguage()->text()
415 if ( $performer->getUser()->isRegistered() ) {
417 $localizer->
msg(
'newarticletext', $helpLink ),
419 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
423 $localizer->
msg(
'newarticletextanon', $helpLink ),
425 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
431 private function addRecreateWarning(
432 IntroMessageList $messages,
434 ProperPageIdentity $page
436 # Give a notice
if the user is editing a deleted/moved page...
437 if ( !$page->exists() ) {
438 $dbr = $this->dbProvider->getReplicaDatabase();
440 $messages->addWithKey(
441 'recreate-moveddeleted-warn',
442 $this->getLogExtract( [
'delete',
'move' ], $page,
'', [
444 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
445 'showIfEmpty' =>
false,
446 'msgKey' => [
'recreate-moveddeleted-warn' ],
452 private function addTalkPageText(
453 IntroMessageList $messages,
457 if ( $title->isTalkPage() ) {
458 $messages->add( $localizer->
msg(
'talkpagetext' ) );
462 private function addEditNotices(
463 IntroMessageList $messages,
466 ?RevisionRecord $revRecord
468 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
469 if ( count( $editNotices ) ) {
470 foreach ( $editNotices as $key => $html ) {
471 $messages->addWithKey( $key, $html );
474 $msg = $localizer->
msg(
'editnotice-notext' );
475 if ( !$msg->isDisabled() ) {
476 $messages->addWithKey(
480 [
'class' =>
'mw-editnotice-notext' ],
488 private function addOldRevisionWarning(
489 IntroMessageList $messages,
491 ?RevisionRecord $revRecord
493 if ( $revRecord && !$revRecord->isCurrent() ) {
495 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->
msg(
'editingold' )->parse() ) );
499 private function addReadOnlyWarning(
500 IntroMessageList $messages,
503 if ( $this->readOnlyMode->isReadOnly() ) {
505 $localizer->
msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
506 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
511 private function addAnonEditWarning(
512 IntroMessageList $messages,
515 Authority $performer,
516 ?
string $returnToQuery,
519 if ( !$performer->
getUser()->isRegistered() ) {
520 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
522 $messages->addWithKey(
525 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
527 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
528 'returnto' => $title->getPrefixedDBkey(),
529 'returntoquery' => $returnToQuery,
532 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
533 'returnto' => $title->getPrefixedDBkey(),
534 'returntoquery' => $returnToQuery,
537 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
540 $messages->addWithKey(
542 $localizer->
msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
544 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
553 private function isWrongCaseUserConfigPage( Title $title ): bool {
554 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
555 $name = $title->getSkinFromConfigSubpage();
556 $skins = array_merge(
557 array_keys( $this->skinFactory->getInstalledSkins() ),
560 return !in_array( $name, $skins,
true )
561 && in_array( strtolower( $name ), $skins,
true );
567 private function addUserConfigPageInfo(
568 IntroMessageList $messages,
571 Authority $performer,
574 if ( $title->isUserConfigPage() ) {
575 # Check the skin exists
576 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
578 $localizer->
msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
579 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
582 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
583 $isUserCssConfig = $title->isUserCssConfigPage();
584 $isUserJsonConfig = $title->isUserJsonConfigPage();
585 $isUserJsConfig = $title->isUserJsConfigPage();
588 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
590 $localizer->
msg(
'usercssyoucanpreview' ),
591 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
593 } elseif ( $isUserJsonConfig ) {
595 $localizer->
msg(
'userjsonyoucanpreview' ),
596 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
598 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
600 $localizer->
msg(
'userjsyoucanpreview' ),
601 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
609 private function addPageProtectionWarningHeaders(
610 IntroMessageList $messages,
612 ProperPageIdentity $page
614 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
615 $this->permManager->getNamespaceRestrictionLevels(
616 $page->getNamespace()
619 # Is the title semi-protected?
620 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
621 $noticeMsg =
'semiprotectedpagewarning';
623 # Then it must be protected based on static groups (regular)
624 $noticeMsg =
'protectedpagewarning';
626 $messages->addWithKey(
628 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
631 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
632 # Is this page under cascading protection from some source pages?
633 $cascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[0];
635 # Explain, and list the titles responsible
636 foreach ( $cascadeSources as
$source ) {
637 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
639 $messages->addWithKey(
640 'cascadeprotectedwarning',
641 $localizer->
msg(
'cascadeprotectedwarning', count( $cascadeSources ) )->parse() .
642 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
643 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
646 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
647 $messages->addWithKey(
648 'titleprotectedwarning',
649 $this->getLogExtract(
654 'showIfEmpty' =>
false,
655 'msgKey' => [
'titleprotectedwarning' ],
656 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
663 private function addHeaderCopyrightWarning(
664 IntroMessageList $messages,
668 $localizer->msg(
'editpage-head-copy-warn' ),
669 "<div class='editpage-head-copywarn'>\n$1\n</div>"