MediaWiki 1.44.0
SpecialRevisionDelete.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
39use RevDelList;
41
50 protected $wasSaved = false;
51
53 private $submitClicked;
54
56 private $ids;
57
59 private $archiveName;
60
62 private $token;
63
65 private $targetObj;
66
68 private $typeName;
69
71 private $checks;
72
74 private $typeLabels;
75
77 private $revDelList;
78
80 private $mIsAllowed;
81
83 private $otherReason;
84
85 private PermissionManager $permissionManager;
86 private RepoGroup $repoGroup;
87
91 private const UI_LABELS = [
92 'revision' => [
93 'check-label' => 'revdelete-hide-text',
94 'success' => 'revdelete-success',
95 'failure' => 'revdelete-failure',
96 'text' => 'revdelete-text-text',
97 'selected' => 'revdelete-selected-text',
98 ],
99 'archive' => [
100 'check-label' => 'revdelete-hide-text',
101 'success' => 'revdelete-success',
102 'failure' => 'revdelete-failure',
103 'text' => 'revdelete-text-text',
104 'selected' => 'revdelete-selected-text',
105 ],
106 'oldimage' => [
107 'check-label' => 'revdelete-hide-image',
108 'success' => 'revdelete-success',
109 'failure' => 'revdelete-failure',
110 'text' => 'revdelete-text-file',
111 'selected' => 'revdelete-selected-file',
112 ],
113 'filearchive' => [
114 'check-label' => 'revdelete-hide-image',
115 'success' => 'revdelete-success',
116 'failure' => 'revdelete-failure',
117 'text' => 'revdelete-text-file',
118 'selected' => 'revdelete-selected-file',
119 ],
120 'logging' => [
121 'check-label' => 'revdelete-hide-name',
122 'success' => 'logdelete-success',
123 'failure' => 'logdelete-failure',
124 'text' => 'logdelete-text',
125 'selected' => 'logdelete-selected',
126 ],
127 ];
128
129 public function __construct( PermissionManager $permissionManager, RepoGroup $repoGroup ) {
130 parent::__construct( 'Revisiondelete' );
131
132 $this->permissionManager = $permissionManager;
133 $this->repoGroup = $repoGroup;
134 }
135
136 public function doesWrites() {
137 return true;
138 }
139
140 public function execute( $par ) {
142
143 $this->checkPermissions();
144 $this->checkReadOnly();
145
146 $output = $this->getOutput();
147 $user = $this->getUser();
148
149 $this->setHeaders();
150 $this->outputHeader();
151 $request = $this->getRequest();
152 $this->submitClicked = $request->wasPosted() && $request->getBool( 'wpSubmit' );
153 # Handle our many different possible input types.
154 $ids = $request->getVal( 'ids' );
155 if ( $ids !== null ) {
156 # Allow CSV, for backwards compatibility, or a single ID for show/hide links
157 $this->ids = explode( ',', $ids );
158 } else {
159 # Array input
160 $this->ids = array_keys( $request->getArray( 'ids', [] ) );
161 }
162 // $this->ids = array_map( 'intval', $this->ids );
163 $this->ids = array_unique( array_filter( $this->ids ) );
164
165 $this->typeName = $request->getVal( 'type' );
166 $this->targetObj = Title::newFromText( $request->getText( 'target' ) );
167
168 # For reviewing deleted files...
169 $this->archiveName = $request->getVal( 'file' );
170 $this->token = $request->getVal( 'token' );
171 if ( $this->archiveName && $this->targetObj ) {
172 $this->tryShowFile( $this->archiveName );
173
174 return;
175 }
176
177 $this->typeName = RevisionDeleter::getCanonicalTypeName( $this->typeName );
178
179 # No targets?
180 if ( !$this->typeName || count( $this->ids ) == 0 ) {
181 throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
182 }
183
184 $restriction = RevisionDeleter::getRestriction( $this->typeName );
185
186 if ( !$this->getAuthority()->isAllowedAny( $restriction, 'deletedhistory' ) ) {
187 throw new PermissionsError( $restriction );
188 }
189
190 # Allow the list type to adjust the passed target
191 $this->targetObj = RevisionDeleter::suggestTarget(
192 $this->typeName,
193 $this->targetObj,
194 $this->ids
195 );
196
197 # We need a target page!
198 if ( $this->targetObj === null ) {
199 $output->addWikiMsg( 'undelete-header' );
200
201 return;
202 }
203
204 // Check blocks
205 $checkReplica = !$this->submitClicked;
206 if (
207 $this->permissionManager->isBlockedFrom(
208 $user,
209 $this->targetObj,
210 $checkReplica
211 )
212 ) {
213 throw new UserBlockedError(
214 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
215 $user->getBlock(),
216 $user,
217 $this->getLanguage(),
218 $request->getIP()
219 );
220 }
221
222 $this->typeLabels = self::UI_LABELS[$this->typeName];
223 $list = $this->getList();
224 $list->reset();
225 $this->mIsAllowed = $this->permissionManager->userHasRight( $user, $restriction );
226 $canViewSuppressedOnly = $this->permissionManager->userHasRight( $user, 'viewsuppressed' ) &&
227 !$this->permissionManager->userHasRight( $user, 'suppressrevision' );
228 $pageIsSuppressed = $list->areAnySuppressed();
229 $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
230
231 $this->otherReason = $request->getVal( 'wpReason', '' );
232 # Give a link to the logs/hist for this page
233 $this->showConvenienceLinks();
234
235 # Initialise checkboxes
236 $this->checks = [
237 # Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name
238 [ $this->typeLabels['check-label'], 'wpHidePrimary',
239 RevisionDeleter::getRevdelConstant( $this->typeName )
240 ],
241 [ 'revdelete-hide-comment', 'wpHideComment', RevisionRecord::DELETED_COMMENT ],
242 [ 'revdelete-hide-user', 'wpHideUser', RevisionRecord::DELETED_USER ]
243 ];
244 if ( $this->permissionManager->userHasRight( $user, 'suppressrevision' ) ) {
245 $this->checks[] = [ 'revdelete-hide-restricted',
246 'wpHideRestricted', RevisionRecord::DELETED_RESTRICTED ];
247 }
248
249 # Either submit or create our form
250 if ( $this->mIsAllowed && $this->submitClicked ) {
251 $this->submit();
252 } else {
253 $this->showForm();
254 }
255
256 if ( $this->permissionManager->userHasRight( $user, 'deletedhistory' ) ) {
257 # Show relevant lines from the deletion log
258 $deleteLogPage = new LogPage( 'delete' );
259 $output->addHTML( "<h2>" . $deleteLogPage->getName()->escaped() . "</h2>\n" );
260 LogEventsList::showLogExtract(
261 $output,
262 'delete',
263 $this->targetObj,
264 '', /* user */
265 [ 'lim' => 25, 'conds' => $this->getLogQueryCond(), 'useMaster' => $this->wasSaved ]
266 );
267 }
268 # Show relevant lines from the suppression log
269 if ( $this->permissionManager->userHasRight( $user, 'suppressionlog' ) ) {
270 $suppressLogPage = new LogPage( 'suppress' );
271 $output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" );
272 LogEventsList::showLogExtract(
273 $output,
274 'suppress',
275 $this->targetObj,
276 '',
277 [ 'lim' => 25, 'conds' => $this->getLogQueryCond(), 'useMaster' => $this->wasSaved ]
278 );
279 }
280 }
281
285 protected function showConvenienceLinks() {
286 $linkRenderer = $this->getLinkRenderer();
287 # Give a link to the logs/hist for this page
288 if ( $this->targetObj ) {
289 // Also set header tabs to be for the target.
290 $this->getSkin()->setRelevantTitle( $this->targetObj );
291
292 $links = [];
293 $links[] = $linkRenderer->makeKnownLink(
295 $this->msg( 'viewpagelogs' )->text(),
296 [],
297 [ 'page' => $this->targetObj->getPrefixedText() ]
298 );
299 if ( !$this->targetObj->isSpecialPage() ) {
300 # Give a link to the page history
301 $links[] = $linkRenderer->makeKnownLink(
302 $this->targetObj,
303 $this->msg( 'pagehist' )->text(),
304 [],
305 [ 'action' => 'history' ]
306 );
307 # Link to deleted edits
308 if ( $this->permissionManager->userHasRight( $this->getUser(), 'undelete' ) ) {
309 $undelete = SpecialPage::getTitleFor( 'Undelete' );
310 $links[] = $linkRenderer->makeKnownLink(
311 $undelete,
312 $this->msg( 'deletedhist' )->text(),
313 [],
314 [ 'target' => $this->targetObj->getPrefixedDBkey() ]
315 );
316 }
317 }
318 # Logs themselves don't have histories or archived revisions
319 $this->getOutput()->addSubtitle( $this->getLanguage()->pipeList( $links ) );
320 }
321 }
322
327 protected function getLogQueryCond() {
328 $conds = [];
329 // Revision delete logs for these item
330 $conds['log_type'] = [ 'delete', 'suppress' ];
331 $conds['log_action'] = $this->getList()->getLogAction();
332 $conds['ls_field'] = RevisionDeleter::getRelationType( $this->typeName );
333 // Convert IDs to strings, since ls_value is a text field. This avoids
334 // a fatal error in PostgreSQL: "operator does not exist: text = integer".
335 $conds['ls_value'] = array_map( 'strval', $this->ids );
336
337 return $conds;
338 }
339
345 protected function tryShowFile( $archiveName ) {
346 $repo = $this->repoGroup->getLocalRepo();
347 $oimage = $repo->newFromArchiveName( $this->targetObj, $archiveName );
348 $oimage->load();
349 // Check if user is allowed to see this file
350 if ( !$oimage->exists() ) {
351 $this->getOutput()->addWikiMsg( 'revdelete-no-file' );
352
353 return;
354 }
355 $user = $this->getUser();
356 if ( !$oimage->userCan( File::DELETED_FILE, $user ) ) {
357 if ( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) {
358 throw new PermissionsError( 'suppressrevision' );
359 } else {
360 throw new PermissionsError( 'deletedtext' );
361 }
362 }
363 if ( !$user->matchEditToken( $this->token, $archiveName ) ) {
364 $lang = $this->getLanguage();
365 $this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
366 $this->targetObj->getText(),
367 $lang->userDate( $oimage->getTimestamp(), $user ),
368 $lang->userTime( $oimage->getTimestamp(), $user ) );
369 $this->getOutput()->addHTML(
370 Html::rawElement( 'form', [
371 'method' => 'POST',
372 'action' => $this->getPageTitle()->getLocalURL( [
373 'target' => $this->targetObj->getPrefixedDBkey(),
374 'file' => $archiveName,
375 'token' => $user->getEditToken( $archiveName ),
376 ] )
377 ],
378 Html::submitButton( $this->msg( 'revdelete-show-file-submit' )->text() )
379 )
380 );
381
382 return;
383 }
384 $this->getOutput()->disable();
385 # We mustn't allow the output to be CDN cached, otherwise
386 # if an admin previews a deleted image, and it's cached, then
387 # a user without appropriate permissions can toddle off and
388 # nab the image, and CDN will serve it
389 $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
390 $this->getRequest()->response()->header(
391 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate'
392 );
393
394 $key = $oimage->getStorageKey();
395 $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
396 $repo->streamFileWithStatus( $path );
397 }
398
403 protected function getList() {
404 if ( $this->revDelList === null ) {
405 $this->revDelList = RevisionDeleter::createList(
406 $this->typeName, $this->getContext(), $this->targetObj, $this->ids
407 );
408 }
409
410 return $this->revDelList;
411 }
412
417 protected function showForm() {
418 $userAllowed = true;
419
420 // Messages: revdelete-selected-text, revdelete-selected-file, logdelete-selected
421 $out = $this->getOutput();
422 $out->wrapWikiMsg( "<strong>$1</strong>", [ $this->typeLabels['selected'],
423 $this->getLanguage()->formatNum( count( $this->ids ) ), $this->targetObj->getPrefixedText() ] );
424
425 $this->addHelpLink( 'Help:RevisionDelete' );
426 $out->addHTML( "<ul>" );
427
428 $numRevisions = 0;
429 // Live revisions...
430 $list = $this->getList();
431 for ( $list->reset(); $list->current(); $list->next() ) {
432 $item = $list->current();
433
434 if ( !$item->canView() ) {
435 if ( !$this->submitClicked ) {
436 throw new PermissionsError( 'suppressrevision' );
437 }
438 $userAllowed = false;
439 }
440
441 $numRevisions++;
442 $out->addHTML( $item->getHTML() );
443 }
444
445 if ( !$numRevisions ) {
446 throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
447 }
448
449 $out->addHTML( "</ul>" );
450 // Explanation text
451 $this->addUsageText();
452
453 // Normal sysops can always see what they did, but can't always change it
454 if ( !$userAllowed ) {
455 return;
456 }
457
458 // Show form if the user can submit
459 if ( $this->mIsAllowed ) {
460 $suppressAllowed = $this->permissionManager
461 ->userHasRight( $this->getUser(), 'suppressrevision' );
462 $out->addModules( [ 'mediawiki.misc-authed-ooui' ] );
463 $out->addModuleStyles( [ 'mediawiki.special',
464 'mediawiki.interface.helpers.styles' ] );
465
466 $dropdownReason = $this->msg( 'revdelete-reason-dropdown' )
467 ->page( $this->targetObj )->inContentLanguage()->text();
468 // Add additional specific reasons for suppress
469 if ( $suppressAllowed ) {
470 $dropdownReason .= "\n" . $this->msg( 'revdelete-reason-dropdown-suppress' )
471 ->page( $this->targetObj )->inContentLanguage()->text();
472 }
473
474 $fields = $this->buildCheckBoxes();
475
476 $fields[] = [
477 'type' => 'select',
478 'label' => $this->msg( 'revdelete-log' )->text(),
479 'cssclass' => 'wpReasonDropDown',
480 'id' => 'wpRevDeleteReasonList',
481 'name' => 'wpRevDeleteReasonList',
482 'options' => Html::listDropdownOptions(
483 $dropdownReason,
484 [ 'other' => $this->msg( 'revdelete-reasonotherlist' )->text() ]
485 ),
486 'default' => $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' )
487 ];
488
489 $fields[] = [
490 'type' => 'text',
491 'label' => $this->msg( 'revdelete-otherreason' )->text(),
492 'name' => 'wpReason',
493 'id' => 'wpReason',
494 // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
495 // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
496 // Unicode codepoints.
497 // "- 155" is to leave room for the 'wpRevDeleteReasonList' value.
498 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT - 155,
499 ];
500
501 $fields[] = [
502 'type' => 'hidden',
503 'name' => 'wpEditToken',
504 'default' => $this->getUser()->getEditToken()
505 ];
506
507 $fields[] = [
508 'type' => 'hidden',
509 'name' => 'target',
510 'default' => $this->targetObj->getPrefixedText()
511 ];
512
513 $fields[] = [
514 'type' => 'hidden',
515 'name' => 'type',
516 'default' => $this->typeName
517 ];
518
519 $fields[] = [
520 'type' => 'hidden',
521 'name' => 'ids',
522 'default' => implode( ',', $this->ids )
523 ];
524
525 $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
526 $htmlForm
527 ->setSubmitText( $this->msg( 'revdelete-submit', $numRevisions )->text() )
528 ->setSubmitName( 'wpSubmit' )
529 ->setWrapperLegend( $this->msg( 'revdelete-legend' )->text() )
530 ->setAction( $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ) )
531 ->loadData();
532 // Show link to edit the dropdown reasons
533 if ( $this->permissionManager->userHasRight( $this->getUser(), 'editinterface' ) ) {
534 $link = '';
535 $linkRenderer = $this->getLinkRenderer();
536 if ( $suppressAllowed ) {
537 $link .= $linkRenderer->makeKnownLink(
538 $this->msg( 'revdelete-reason-dropdown-suppress' )->inContentLanguage()->getTitle(),
539 $this->msg( 'revdelete-edit-reasonlist-suppress' )->text(),
540 [],
541 [ 'action' => 'edit' ]
542 );
543 $link .= $this->msg( 'pipe-separator' )->escaped();
544 }
545 $link .= $linkRenderer->makeKnownLink(
546 $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
547 $this->msg( 'revdelete-edit-reasonlist' )->text(),
548 [],
549 [ 'action' => 'edit' ]
550 );
551 $htmlForm->setPostHtml( Html::rawElement( 'p', [ 'class' => 'mw-revdel-editreasons' ], $link ) );
552 }
553 $out->addHTML( $htmlForm->getHTML( false ) );
554 }
555 }
556
561 protected function addUsageText() {
562 // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
563 $this->getOutput()->wrapWikiMsg(
564 "<strong>$1</strong>\n$2", $this->typeLabels['text'],
565 'revdelete-text-others'
566 );
567
568 if ( $this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' ) ) {
569 $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
570 }
571
572 if ( $this->mIsAllowed ) {
573 $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
574 }
575 }
576
580 protected function buildCheckBoxes() {
581 $fields = [];
582
583 $type = 'radio';
584
585 $list = $this->getList();
586
587 // If there is just one item, use checkboxes
588 if ( $list->length() == 1 ) {
589 $list->reset();
590
591 $type = 'check';
592 }
593
594 foreach ( $this->checks as $item ) {
595 // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
596 // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
597 [ $message, $name, $bitField ] = $item;
598
599 $field = [
600 'type' => $type,
601 'label-raw' => $this->msg( $message )->escaped(),
602 'id' => $name,
603 'flatlist' => true,
604 'name' => $name,
605 'default' => $list->length() == 1 ? $list->current()->getBits() & $bitField : null
606 ];
607
608 if ( $bitField == RevisionRecord::DELETED_RESTRICTED ) {
609 $field['label-raw'] = "<b>" . $field['label-raw'] . "</b>";
610 if ( $type === 'radio' ) {
611 $field['options-messages'] = [
612 'revdelete-radio-same' => -1,
613 'revdelete-radio-unset-suppress' => 0,
614 'revdelete-radio-set-suppress' => 1
615 ];
616 }
617 } elseif ( $type === 'radio' ) {
618 $field['options-messages'] = [
619 'revdelete-radio-same' => -1,
620 'revdelete-radio-unset' => 0,
621 'revdelete-radio-set' => 1
622 ];
623 }
624
625 $fields[] = $field;
626 }
627
628 return $fields;
629 }
630
636 protected function submit() {
637 # Check edit token on submission
638 $token = $this->getRequest()->getVal( 'wpEditToken' );
639 if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
640 $this->getOutput()->addWikiMsg( 'sessionfailure' );
641
642 return false;
643 }
644 $bitParams = $this->extractBitParams();
645 // from dropdown
646 $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
647 $comment = $listReason;
648 if ( $comment === 'other' ) {
649 $comment = $this->otherReason;
650 } elseif ( $this->otherReason !== '' ) {
651 // Entry from drop down menu + additional comment
652 $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
653 . $this->otherReason;
654 }
655 # Can the user set this field?
656 if ( $bitParams[RevisionRecord::DELETED_RESTRICTED] == 1
657 && !$this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' )
658 ) {
659 throw new PermissionsError( 'suppressrevision' );
660 }
661 # If the save went through, go to success message...
662 $status = $this->save( $bitParams, $comment );
663 if ( $status->isGood() ) {
664 $this->success();
665
666 return true;
667 } else {
668 # ...otherwise, bounce back to form...
669 $this->failure( $status );
670 }
671
672 return false;
673 }
674
678 protected function success() {
679 // Messages: revdelete-success, logdelete-success
680 $out = $this->getOutput();
681 $out->setPageTitleMsg( $this->msg( 'actioncomplete' ) );
682 $out->addHTML(
683 Html::successBox(
684 $out->msg( $this->typeLabels['success'] )->parse()
685 )
686 );
687 $this->wasSaved = true;
688 $this->revDelList->reloadFromPrimary();
689 $this->showForm();
690 }
691
696 protected function failure( $status ) {
697 // Messages: revdelete-failure, logdelete-failure
698 $out = $this->getOutput();
699 $out->setPageTitleMsg( $this->msg( 'actionfailed' ) );
700 $out->addModuleStyles( 'mediawiki.codex.messagebox.styles' );
701 $out->addHTML(
702 Html::errorBox(
703 $out->parseAsContent(
704 $status->getWikiText( $this->typeLabels['failure'], false, $this->getLanguage() )
705 )
706 )
707 );
708 $this->showForm();
709 }
710
716 protected function extractBitParams() {
717 $bitfield = [];
718 foreach ( $this->checks as [ /* message */, $name, $field ] ) {
719 $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
720 if ( $val < -1 || $val > 1 ) {
721 $val = -1; // -1 for existing value
722 }
723 $bitfield[$field] = $val;
724 }
725 if ( !isset( $bitfield[RevisionRecord::DELETED_RESTRICTED] ) ) {
726 $bitfield[RevisionRecord::DELETED_RESTRICTED] = 0;
727 }
728
729 return $bitfield;
730 }
731
738 protected function save( array $bitPars, $reason ) {
739 return $this->getList()->setVisibility(
740 [ 'value' => $bitPars, 'comment' => $reason ]
741 );
742 }
743
744 protected function getGroupName() {
745 return 'pagetools';
746 }
747}
748
753class_alias( SpecialRevisionDelete::class, 'SpecialRevisionDelete' );
Handle database storage of comments such as edit summaries and log reasons.
An error page which can definitely be safely rendered using the OutputPage.
Show an error when a user tries to do something they do not have the necessary permissions for.
Show an error when the user tries to do something whilst blocked.
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:93
Prioritized list of file repositories.
Definition RepoGroup.php:38
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:209
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
Class to simplify the use of log pages.
Definition LogPage.php:50
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Page revision base class.
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getSkin()
Shortcut to get the skin being used for this instance.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getUser()
Shortcut to get the User executing this instance.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
getPageTitle( $subpage=false)
Get a self-referential title object.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Shortcut to construct a special page which is unlisted by default.
Special page allowing users with the appropriate permissions to view and hide revisions.
doesWrites()
Indicates whether POST requests to this special page require write access to the wiki.
showForm()
Show a list of items that we will operate on, and show a form with checkboxes which will allow the us...
extractBitParams()
Put together an array that contains -1, 0, or the *_deleted const for each bit.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
getLogQueryCond()
Get the condition used for fetching log snippets.
failure( $status)
Report that the submit operation failed.
save(array $bitPars, $reason)
Do the write operations.
execute( $par)
Default execute method Checks user permissions.
tryShowFile( $archiveName)
Show a deleted file version requested by the visitor.
success()
Report that the submit operation succeeded.
submit()
UI entry point for form submission.
getList()
Get the list object for this request.
bool $wasSaved
Was the DB modified in this request.
__construct(PermissionManager $permissionManager, RepoGroup $repoGroup)
showConvenienceLinks()
Show some useful links in the subtitle.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Represents a title within MediaWiki.
Definition Title.php:78
General controller for RevDel, used by both SpecialRevisiondelete and ApiRevisionDelete.