107 $this->mArticle = $article;
108 $this->mTitle = $article->
getTitle();
109 $this->mApplicableTypes = $this->mTitle->getRestrictionTypes();
111 $this->mRequest = $this->mContext->getRequest();
112 $this->mPerformer = $this->mContext->getAuthority();
113 $this->mOut = $this->mContext->getOutput();
114 $this->mLang = $this->mContext->getLanguage();
116 $services = MediaWikiServices::getInstance();
117 $this->permManager = $services->getPermissionManager();
118 $this->hookRunner =
new HookRunner( $services->getHookContainer() );
119 $this->watchlistManager = $services->getWatchlistManager();
123 $this->mPermStatus = PermissionStatus::newEmpty();
124 if ( $this->mRequest->wasPosted() ) {
125 $this->mPerformer->authorizeWrite(
'protect', $this->mTitle, $this->mPermStatus );
127 $this->mPerformer->authorizeRead(
'protect', $this->mTitle, $this->mPermStatus );
132 $this->disabled = !$this->mPermStatus->isGood();
133 $this->disabledAttrib = $this->disabled ? [
'disabled' =>
'disabled' ] : [];
142 $levels = $this->permManager->getNamespaceRestrictionLevels(
143 $this->mTitle->getNamespace(), $this->mPerformer->getUser()
146 $this->mCascade = $this->mTitle->areRestrictionsCascading();
147 $this->mReason = $this->mRequest->getText(
'mwProtect-reason' );
148 $this->mReasonSelection = $this->mRequest->getText(
'wpProtectReasonSelection' );
149 $this->mCascade = $this->mRequest->getBool(
'mwProtect-cascade', $this->mCascade );
151 foreach ( $this->mApplicableTypes as $action ) {
156 $this->mRestrictions[$action] = implode(
'', $this->mTitle->getRestrictions( $action ) );
158 if ( !$this->mRestrictions[$action] ) {
160 $existingExpiry =
'';
162 $existingExpiry = $this->mTitle->getRestrictionExpiry( $action );
164 $this->mExistingExpiry[$action] = $existingExpiry;
166 $requestExpiry = $this->mRequest->getText(
"mwProtect-expiry-$action" );
167 $requestExpirySelection = $this->mRequest->getVal(
"wpProtectExpirySelection-$action" );
169 if ( $requestExpiry ) {
171 $this->mExpiry[$action] = $requestExpiry;
172 $this->mExpirySelection[$action] =
'othertime';
173 } elseif ( $requestExpirySelection ) {
175 $this->mExpiry[$action] =
'';
176 $this->mExpirySelection[$action] = $requestExpirySelection;
177 } elseif ( $existingExpiry ) {
179 $this->mExpiry[$action] =
'';
180 $this->mExpirySelection[$action] = $existingExpiry;
184 $this->mExpiry[$action] =
'';
185 $this->mExpirySelection[$action] =
'infinite';
188 $val = $this->mRequest->getVal(
"mwProtect-level-$action" );
189 if ( isset( $val ) && in_array( $val, $levels ) ) {
190 $this->mRestrictions[$action] = $val;
253 private function show( $err =
null ) {
256 $out->addBacklinkSubtitle( $this->mTitle );
258 if ( is_array( $err ) ) {
259 $out->addHTML( Html::errorBox( $out->msg( ...$err )->parse() ) );
260 } elseif ( is_string( $err ) ) {
261 $out->addHTML( Html::errorBox( $err ) );
264 if ( $this->mApplicableTypes === [] ) {
267 $out->setPageTitle( $this->mContext->msg(
268 'protect-norestrictiontypes-title',
269 $this->mTitle->getPrefixedText()
271 $out->addWikiTextAsInterface(
272 $this->mContext->msg(
'protect-norestrictiontypes-text' )->plain()
281 list( $cascadeSources, ) = $this->mTitle->getCascadeProtectionSources();
282 if ( $cascadeSources && count( $cascadeSources ) > 0 ) {
285 foreach ( $cascadeSources as
$title ) {
286 $titles .=
'* [[:' .
$title->getPrefixedText() .
"]]\n";
291 "<div id=\"mw-protect-cascadeon\">\n$1\n" . $titles .
"</div>",
292 [
'protect-cascadeon', count( $cascadeSources ) ]
296 # Show an appropriate message if the user isn't allowed or able to change
297 # the protection settings at this time
298 if ( $this->disabled ) {
300 $this->mContext->msg(
'protect-title-notallowed',
301 $this->mTitle->getPrefixedText() )
303 $out->addWikiTextAsInterface(
304 $out->formatPermissionStatus( $this->mPermStatus,
'protect' )
308 $this->mContext->msg(
'protect-title', $this->mTitle->getPrefixedText() )
310 $out->addWikiMsg(
'protect-text',
325 if ( $this->disabled ) {
330 $token = $this->mRequest->getVal(
'wpEditToken' );
331 $legacyUser = MediaWikiServices::getInstance()
333 ->newFromAuthority( $this->mPerformer );
334 if ( !$legacyUser->matchEditToken( $token, [
'protect', $this->mTitle->getPrefixedDBkey() ] ) ) {
335 $this->
show( [
'sessionfailure' ] );
339 # Create reason string. Use list and/or custom string.
341 if ( $reasonstr !=
'other' && $this->mReason !=
'' ) {
343 $reasonstr .= $this->mContext->msg(
'colon-separator' )->text() .
$this->mReason;
344 } elseif ( $reasonstr ==
'other' ) {
349 foreach ( $this->mApplicableTypes as $action ) {
350 $expiry[$action] = $this->
getExpiry( $action );
351 if ( empty( $this->mRestrictions[$action] ) ) {
355 if ( !$expiry[$action] ) {
356 $this->
show( [
'protect_expiry_invalid' ] );
360 $this->
show( [
'protect_expiry_old' ] );
365 $this->mCascade = $this->mRequest->getBool(
'mwProtect-cascade' );
367 $status = $this->mArticle->getPage()->doUpdateRestrictions(
368 $this->mRestrictions,
372 $this->mPerformer->getUser()
375 if ( !$status->isOK() ) {
376 $this->
show( $this->mOut->parseInlineAsInterface(
377 $status->getWikiText(
false,
false, $this->mLang )
389 if ( !$this->hookRunner->onProtectionForm__save( $this->mArticle, $errorMsg, $reasonstr ) ) {
390 if ( $errorMsg ==
'' ) {
391 $errorMsg = [
'hookaborted' ];
394 if ( $errorMsg !=
'' ) {
395 $this->
show( $errorMsg );
399 $this->watchlistManager->setWatch(
400 $this->mRequest->getCheck(
'mwProtectWatch' ),
414 $this->mOut->enableOOUI();
417 if ( !$this->disabled ) {
418 $this->mOut->addModules(
'mediawiki.action.protect' );
419 $this->mOut->addModuleStyles(
'mediawiki.action.styles' );
421 $scExpiryOptions = $this->mContext->msg(
'protect-expiry-options' )->inContentLanguage()->text();
422 $levels = $this->permManager->getNamespaceRestrictionLevels(
423 $this->mTitle->getNamespace(),
424 $this->disabled ?
null : $this->mPerformer->getUser()
428 foreach ( $this->mRestrictions as $action => $selected ) {
431 $section =
'restriction-' . $action;
432 $id =
'mwProtect-level-' . $action;
434 foreach ( $levels as $key ) {
441 'default' => $selected,
443 'size' => count( $levels ),
444 'options' => $options,
446 'section' => $section,
451 if ( $this->mExistingExpiry[$action] ) {
452 if ( $this->mExistingExpiry[$action] ==
'infinity' ) {
453 $existingExpiryMessage = $this->mContext->msg(
'protect-existing-expiry-infinity' );
455 $existingExpiryMessage = $this->mContext->msg(
'protect-existing-expiry' )
456 ->dateTimeParams( $this->mExistingExpiry[$action] )
457 ->dateParams( $this->mExistingExpiry[$action] )
458 ->timeParams( $this->mExistingExpiry[$action] );
460 $expiryOptions[$existingExpiryMessage->text()] =
'existing';
463 $expiryOptions[$this->mContext->msg(
'protect-othertime-op' )->text()] =
'othertime';
467 # Add expiry dropdown
468 $fields[
"wpProtectExpirySelection-$action"] = [
470 'name' =>
"wpProtectExpirySelection-$action",
471 'id' =>
"mwProtectExpirySelection-$action",
474 'label' => $this->mContext->msg(
'protectexpiry' )->text(),
475 'options' => $expiryOptions,
476 'default' => $this->mExpirySelection[$action],
477 'section' => $section,
480 # Add custom expiry field
481 if ( !$this->disabled ) {
482 $fields[
"mwProtect-expiry-$action"] = [
484 'label' => $this->mContext->msg(
'protect-othertime' )->text(),
485 'name' =>
"mwProtect-expiry-$action",
486 'id' =>
"mwProtect-$action-expires",
488 'default' => $this->mExpiry[$action],
490 'section' => $section,
495 # Give extensions a chance to add items to the form
497 $hookFormOptions = [];
499 $this->hookRunner->onProtectionForm__buildForm( $this->mArticle, $hookFormRaw );
500 $this->hookRunner->onProtectionFormAddFormFields( $this->mArticle, $hookFormOptions );
502 # Merge forms added from addFormFields
503 $fields = array_merge( $fields, $hookFormOptions );
505 # Add raw sections added in buildForm
506 if ( $hookFormRaw ) {
507 $fields[
'rawinfo'] = [
509 'default' => $hookFormRaw,
511 'section' =>
'restriction-blank'
515 # JavaScript will add another row with a value-chaining checkbox
516 if ( $this->mTitle->exists() ) {
517 $fields[
'mwProtect-cascade'] = [
519 'label' => $this->mContext->msg(
'protect-cascade' )->text(),
520 'id' =>
'mwProtect-cascade',
521 'name' =>
'mwProtect-cascade',
527 # Add manual and custom reason field/selects as well as submit
528 if ( !$this->disabled ) {
534 $maxlength = CommentStore::COMMENT_CHARACTER_LIMIT - 75;
535 $fields[
'wpProtectReasonSelection'] = [
537 'cssclass' =>
'mwProtect-reason',
538 'label' => $this->mContext->msg(
'protectcomment' )->text(),
540 'id' =>
'wpProtectReasonSelection',
541 'name' =>
'wpProtectReasonSelection',
543 'options' => Xml::listDropDownOptions(
544 $this->mContext->msg(
'protect-dropdown' )->inContentLanguage()->text(),
545 [
'other' => $this->mContext->msg(
'protect-otherreason-op' )->inContentLanguage()->text() ]
549 $fields[
'mwProtect-reason'] = [
551 'id' =>
'mwProtect-reason',
552 'label' => $this->mContext->msg(
'protect-otherreason' )->text(),
553 'name' =>
'mwProtect-reason',
555 'maxlength' => $maxlength,
558 # Disallow watching if user is not logged in
559 if ( $this->mPerformer->getUser()->isRegistered() ) {
560 $fields[
'mwProtectWatch'] = [
562 'id' =>
'mwProtectWatch',
563 'label' => $this->mContext->msg(
'watchthis' )->text(),
564 'name' =>
'mwProtectWatch',
566 $this->watchlistManager->isWatched( $this->mPerformer, $this->mTitle )
567 || MediaWikiServices::getInstance()->getUserOptionsLookup()->getOption(
568 $this->mPerformer->getUser(),
576 if ( $this->mPerformer->isAllowed(
'editinterface' ) ) {
577 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
578 $link = $linkRenderer->makeKnownLink(
579 $this->mContext->msg(
'protect-dropdown' )->inContentLanguage()->getTitle(),
580 $this->mContext->msg(
'protect-edit-reasonlist' )->text(),
582 [
'action' =>
'edit' ]
584 $out .=
'<p class="mw-protect-editreasons">' . $link .
'</p>';
587 if ( !$this->disabled ) {
588 $legacyUser = MediaWikiServices::getInstance()
590 ->newFromAuthority( $this->mPerformer );
591 $fields[
'wpEditToken'] = [
592 'name' =>
'wpEditToken',
594 'default' => $legacyUser->getEditToken( [
'protect', $this->mTitle->getPrefixedDBkey() ] ),
598 $htmlForm = HTMLForm::factory(
'ooui', $fields, $this->mContext );
600 ->setMethod(
'post' )
601 ->setId(
'mw-Protect-Form' )
602 ->setTableId(
'mw-protect-table2' )
603 ->setAction( $this->mTitle->getLocalURL(
'action=protect' ) )
604 ->setSubmitID(
'mw-Protect-submit' )
605 ->setSubmitTextMsg(
'confirm' )
606 ->suppressDefaultSubmit( $this->disabled )
607 ->setWrapperLegendMsg(
'protect-legend' )
610 return $htmlForm->getHTML(
false ) . $out;