MediaWiki master
SpecialRevisionDelete.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
24use File;
26use LogPage;
38use RepoGroup;
39use RevDelList;
42
51 protected $wasSaved = false;
52
54 private $submitClicked;
55
57 private $ids;
58
60 private $archiveName;
61
63 private $token;
64
66 private $targetObj;
67
69 private $typeName;
70
72 private $checks;
73
75 private $typeLabels;
76
78 private $revDelList;
79
81 private $mIsAllowed;
82
84 private $otherReason;
85
86 private PermissionManager $permissionManager;
87 private RepoGroup $repoGroup;
88
92 private const UI_LABELS = [
93 'revision' => [
94 'check-label' => 'revdelete-hide-text',
95 'success' => 'revdelete-success',
96 'failure' => 'revdelete-failure',
97 'text' => 'revdelete-text-text',
98 'selected' => 'revdelete-selected-text',
99 ],
100 'archive' => [
101 'check-label' => 'revdelete-hide-text',
102 'success' => 'revdelete-success',
103 'failure' => 'revdelete-failure',
104 'text' => 'revdelete-text-text',
105 'selected' => 'revdelete-selected-text',
106 ],
107 'oldimage' => [
108 'check-label' => 'revdelete-hide-image',
109 'success' => 'revdelete-success',
110 'failure' => 'revdelete-failure',
111 'text' => 'revdelete-text-file',
112 'selected' => 'revdelete-selected-file',
113 ],
114 'filearchive' => [
115 'check-label' => 'revdelete-hide-image',
116 'success' => 'revdelete-success',
117 'failure' => 'revdelete-failure',
118 'text' => 'revdelete-text-file',
119 'selected' => 'revdelete-selected-file',
120 ],
121 'logging' => [
122 'check-label' => 'revdelete-hide-name',
123 'success' => 'logdelete-success',
124 'failure' => 'logdelete-failure',
125 'text' => 'logdelete-text',
126 'selected' => 'logdelete-selected',
127 ],
128 ];
129
136 public function __construct( PermissionManager $permissionManager, RepoGroup $repoGroup ) {
137 parent::__construct( 'Revisiondelete' );
138
139 $this->permissionManager = $permissionManager;
140 $this->repoGroup = $repoGroup;
141 }
142
143 public function doesWrites() {
144 return true;
145 }
146
147 public function execute( $par ) {
149
150 $this->checkPermissions();
151 $this->checkReadOnly();
152
153 $output = $this->getOutput();
154 $user = $this->getUser();
155
156 $this->setHeaders();
157 $this->outputHeader();
158 $request = $this->getRequest();
159 $this->submitClicked = $request->wasPosted() && $request->getBool( 'wpSubmit' );
160 # Handle our many different possible input types.
161 $ids = $request->getVal( 'ids' );
162 if ( $ids !== null ) {
163 # Allow CSV, for backwards compatibility, or a single ID for show/hide links
164 $this->ids = explode( ',', $ids );
165 } else {
166 # Array input
167 $this->ids = array_keys( $request->getArray( 'ids', [] ) );
168 }
169 // $this->ids = array_map( 'intval', $this->ids );
170 $this->ids = array_unique( array_filter( $this->ids ) );
171
172 $this->typeName = $request->getVal( 'type' );
173 $this->targetObj = Title::newFromText( $request->getText( 'target' ) );
174
175 # For reviewing deleted files...
176 $this->archiveName = $request->getVal( 'file' );
177 $this->token = $request->getVal( 'token' );
178 if ( $this->archiveName && $this->targetObj ) {
179 $this->tryShowFile( $this->archiveName );
180
181 return;
182 }
183
184 $this->typeName = RevisionDeleter::getCanonicalTypeName( $this->typeName );
185
186 # No targets?
187 if ( !$this->typeName || count( $this->ids ) == 0 ) {
188 throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
189 }
190
191 $restriction = RevisionDeleter::getRestriction( $this->typeName );
192
193 if ( !$this->getAuthority()->isAllowedAny( $restriction, 'deletedhistory' ) ) {
194 throw new PermissionsError( $restriction );
195 }
196
197 # Allow the list type to adjust the passed target
198 $this->targetObj = RevisionDeleter::suggestTarget(
199 $this->typeName,
200 $this->targetObj,
201 $this->ids
202 );
203
204 # We need a target page!
205 if ( $this->targetObj === null ) {
206 $output->addWikiMsg( 'undelete-header' );
207
208 return;
209 }
210
211 // Check blocks
212 $checkReplica = !$this->submitClicked;
213 if (
214 $this->permissionManager->isBlockedFrom(
215 $user,
216 $this->targetObj,
217 $checkReplica
218 )
219 ) {
220 throw new UserBlockedError(
221 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
222 $user->getBlock(),
223 $user,
224 $this->getLanguage(),
225 $request->getIP()
226 );
227 }
228
229 $this->typeLabels = self::UI_LABELS[$this->typeName];
230 $list = $this->getList();
231 $list->reset();
232 $this->mIsAllowed = $this->permissionManager->userHasRight( $user, $restriction );
233 $canViewSuppressedOnly = $this->permissionManager->userHasRight( $user, 'viewsuppressed' ) &&
234 !$this->permissionManager->userHasRight( $user, 'suppressrevision' );
235 $pageIsSuppressed = $list->areAnySuppressed();
236 $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
237
238 $this->otherReason = $request->getVal( 'wpReason', '' );
239 # Give a link to the logs/hist for this page
240 $this->showConvenienceLinks();
241
242 # Initialise checkboxes
243 $this->checks = [
244 # Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name
245 [ $this->typeLabels['check-label'], 'wpHidePrimary',
246 RevisionDeleter::getRevdelConstant( $this->typeName )
247 ],
248 [ 'revdelete-hide-comment', 'wpHideComment', RevisionRecord::DELETED_COMMENT ],
249 [ 'revdelete-hide-user', 'wpHideUser', RevisionRecord::DELETED_USER ]
250 ];
251 if ( $this->permissionManager->userHasRight( $user, 'suppressrevision' ) ) {
252 $this->checks[] = [ 'revdelete-hide-restricted',
253 'wpHideRestricted', RevisionRecord::DELETED_RESTRICTED ];
254 }
255
256 # Either submit or create our form
257 if ( $this->mIsAllowed && $this->submitClicked ) {
258 $this->submit();
259 } else {
260 $this->showForm();
261 }
262
263 if ( $this->permissionManager->userHasRight( $user, 'deletedhistory' ) ) {
264 # Show relevant lines from the deletion log
265 $deleteLogPage = new LogPage( 'delete' );
266 $output->addHTML( "<h2>" . $deleteLogPage->getName()->escaped() . "</h2>\n" );
267 LogEventsList::showLogExtract(
268 $output,
269 'delete',
270 $this->targetObj,
271 '', /* user */
272 [ 'lim' => 25, 'conds' => $this->getLogQueryCond(), 'useMaster' => $this->wasSaved ]
273 );
274 }
275 # Show relevant lines from the suppression log
276 if ( $this->permissionManager->userHasRight( $user, 'suppressionlog' ) ) {
277 $suppressLogPage = new LogPage( 'suppress' );
278 $output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" );
279 LogEventsList::showLogExtract(
280 $output,
281 'suppress',
282 $this->targetObj,
283 '',
284 [ 'lim' => 25, 'conds' => $this->getLogQueryCond(), 'useMaster' => $this->wasSaved ]
285 );
286 }
287 }
288
292 protected function showConvenienceLinks() {
293 $linkRenderer = $this->getLinkRenderer();
294 # Give a link to the logs/hist for this page
295 if ( $this->targetObj ) {
296 // Also set header tabs to be for the target.
297 $this->getSkin()->setRelevantTitle( $this->targetObj );
298
299 $links = [];
300 $links[] = $linkRenderer->makeKnownLink(
302 $this->msg( 'viewpagelogs' )->text(),
303 [],
304 [ 'page' => $this->targetObj->getPrefixedText() ]
305 );
306 if ( !$this->targetObj->isSpecialPage() ) {
307 # Give a link to the page history
308 $links[] = $linkRenderer->makeKnownLink(
309 $this->targetObj,
310 $this->msg( 'pagehist' )->text(),
311 [],
312 [ 'action' => 'history' ]
313 );
314 # Link to deleted edits
315 if ( $this->permissionManager->userHasRight( $this->getUser(), 'undelete' ) ) {
316 $undelete = SpecialPage::getTitleFor( 'Undelete' );
317 $links[] = $linkRenderer->makeKnownLink(
318 $undelete,
319 $this->msg( 'deletedhist' )->text(),
320 [],
321 [ 'target' => $this->targetObj->getPrefixedDBkey() ]
322 );
323 }
324 }
325 # Logs themselves don't have histories or archived revisions
326 $this->getOutput()->addSubtitle( $this->getLanguage()->pipeList( $links ) );
327 }
328 }
329
334 protected function getLogQueryCond() {
335 $conds = [];
336 // Revision delete logs for these item
337 $conds['log_type'] = [ 'delete', 'suppress' ];
338 $conds['log_action'] = $this->getList()->getLogAction();
339 $conds['ls_field'] = RevisionDeleter::getRelationType( $this->typeName );
340 // Convert IDs to strings, since ls_value is a text field. This avoids
341 // a fatal error in PostgreSQL: "operator does not exist: text = integer".
342 $conds['ls_value'] = array_map( 'strval', $this->ids );
343
344 return $conds;
345 }
346
352 protected function tryShowFile( $archiveName ) {
353 $repo = $this->repoGroup->getLocalRepo();
354 $oimage = $repo->newFromArchiveName( $this->targetObj, $archiveName );
355 $oimage->load();
356 // Check if user is allowed to see this file
357 if ( !$oimage->exists() ) {
358 $this->getOutput()->addWikiMsg( 'revdelete-no-file' );
359
360 return;
361 }
362 $user = $this->getUser();
363 if ( !$oimage->userCan( File::DELETED_FILE, $user ) ) {
364 if ( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) {
365 throw new PermissionsError( 'suppressrevision' );
366 } else {
367 throw new PermissionsError( 'deletedtext' );
368 }
369 }
370 if ( !$user->matchEditToken( $this->token, $archiveName ) ) {
371 $lang = $this->getLanguage();
372 $this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
373 $this->targetObj->getText(),
374 $lang->userDate( $oimage->getTimestamp(), $user ),
375 $lang->userTime( $oimage->getTimestamp(), $user ) );
376 $this->getOutput()->addHTML(
377 Html::rawElement( 'form', [
378 'method' => 'POST',
379 'action' => $this->getPageTitle()->getLocalURL( [
380 'target' => $this->targetObj->getPrefixedDBkey(),
381 'file' => $archiveName,
382 'token' => $user->getEditToken( $archiveName ),
383 ] )
384 ],
385 Xml::submitButton( $this->msg( 'revdelete-show-file-submit' )->text() )
386 )
387 );
388
389 return;
390 }
391 $this->getOutput()->disable();
392 # We mustn't allow the output to be CDN cached, otherwise
393 # if an admin previews a deleted image, and it's cached, then
394 # a user without appropriate permissions can toddle off and
395 # nab the image, and CDN will serve it
396 $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
397 $this->getRequest()->response()->header(
398 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate'
399 );
400
401 $key = $oimage->getStorageKey();
402 $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
403 $repo->streamFileWithStatus( $path );
404 }
405
410 protected function getList() {
411 if ( $this->revDelList === null ) {
412 $this->revDelList = RevisionDeleter::createList(
413 $this->typeName, $this->getContext(), $this->targetObj, $this->ids
414 );
415 }
416
417 return $this->revDelList;
418 }
419
424 protected function showForm() {
425 $userAllowed = true;
426
427 // Messages: revdelete-selected-text, revdelete-selected-file, logdelete-selected
428 $out = $this->getOutput();
429 $out->wrapWikiMsg( "<strong>$1</strong>", [ $this->typeLabels['selected'],
430 $this->getLanguage()->formatNum( count( $this->ids ) ), $this->targetObj->getPrefixedText() ] );
431
432 $this->addHelpLink( 'Help:RevisionDelete' );
433 $out->addHTML( "<ul>" );
434
435 $numRevisions = 0;
436 // Live revisions...
437 $list = $this->getList();
438 for ( $list->reset(); $list->current(); $list->next() ) {
439 $item = $list->current();
440
441 if ( !$item->canView() ) {
442 if ( !$this->submitClicked ) {
443 throw new PermissionsError( 'suppressrevision' );
444 }
445 $userAllowed = false;
446 }
447
448 $numRevisions++;
449 $out->addHTML( $item->getHTML() );
450 }
451
452 if ( !$numRevisions ) {
453 throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
454 }
455
456 $out->addHTML( "</ul>" );
457 // Explanation text
458 $this->addUsageText();
459
460 // Normal sysops can always see what they did, but can't always change it
461 if ( !$userAllowed ) {
462 return;
463 }
464
465 // Show form if the user can submit
466 if ( $this->mIsAllowed ) {
467 $suppressAllowed = $this->permissionManager
468 ->userHasRight( $this->getUser(), 'suppressrevision' );
469 $out->addModules( [ 'mediawiki.misc-authed-ooui' ] );
470 $out->addModuleStyles( [ 'mediawiki.special',
471 'mediawiki.interface.helpers.styles' ] );
472
473 $dropdownReason = $this->msg( 'revdelete-reason-dropdown' )
474 ->page( $this->targetObj )->inContentLanguage()->text();
475 // Add additional specific reasons for suppress
476 if ( $suppressAllowed ) {
477 $dropdownReason .= "\n" . $this->msg( 'revdelete-reason-dropdown-suppress' )
478 ->page( $this->targetObj )->inContentLanguage()->text();
479 }
480
481 $fields = $this->buildCheckBoxes();
482
483 $fields[] = [
484 'type' => 'select',
485 'label' => $this->msg( 'revdelete-log' )->text(),
486 'cssclass' => 'wpReasonDropDown',
487 'id' => 'wpRevDeleteReasonList',
488 'name' => 'wpRevDeleteReasonList',
489 'options' => Html::listDropdownOptions(
490 $dropdownReason,
491 [ 'other' => $this->msg( 'revdelete-reasonotherlist' )->text() ]
492 ),
493 'default' => $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' )
494 ];
495
496 $fields[] = [
497 'type' => 'text',
498 'label' => $this->msg( 'revdelete-otherreason' )->text(),
499 'name' => 'wpReason',
500 'id' => 'wpReason',
501 // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
502 // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
503 // Unicode codepoints.
504 // "- 155" is to leave room for the 'wpRevDeleteReasonList' value.
505 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT - 155,
506 ];
507
508 $fields[] = [
509 'type' => 'hidden',
510 'name' => 'wpEditToken',
511 'default' => $this->getUser()->getEditToken()
512 ];
513
514 $fields[] = [
515 'type' => 'hidden',
516 'name' => 'target',
517 'default' => $this->targetObj->getPrefixedText()
518 ];
519
520 $fields[] = [
521 'type' => 'hidden',
522 'name' => 'type',
523 'default' => $this->typeName
524 ];
525
526 $fields[] = [
527 'type' => 'hidden',
528 'name' => 'ids',
529 'default' => implode( ',', $this->ids )
530 ];
531
532 $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
533 $htmlForm
534 ->setSubmitText( $this->msg( 'revdelete-submit', $numRevisions )->text() )
535 ->setSubmitName( 'wpSubmit' )
536 ->setWrapperLegend( $this->msg( 'revdelete-legend' )->text() )
537 ->setAction( $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ) )
538 ->loadData();
539 // Show link to edit the dropdown reasons
540 if ( $this->permissionManager->userHasRight( $this->getUser(), 'editinterface' ) ) {
541 $link = '';
542 $linkRenderer = $this->getLinkRenderer();
543 if ( $suppressAllowed ) {
544 $link .= $linkRenderer->makeKnownLink(
545 $this->msg( 'revdelete-reason-dropdown-suppress' )->inContentLanguage()->getTitle(),
546 $this->msg( 'revdelete-edit-reasonlist-suppress' )->text(),
547 [],
548 [ 'action' => 'edit' ]
549 );
550 $link .= $this->msg( 'pipe-separator' )->escaped();
551 }
552 $link .= $linkRenderer->makeKnownLink(
553 $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
554 $this->msg( 'revdelete-edit-reasonlist' )->text(),
555 [],
556 [ 'action' => 'edit' ]
557 );
558 $htmlForm->setPostHtml( Xml::tags( 'p', [ 'class' => 'mw-revdel-editreasons' ], $link ) );
559 }
560 $out->addHTML( $htmlForm->getHTML( false ) );
561 }
562 }
563
568 protected function addUsageText() {
569 // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
570 $this->getOutput()->wrapWikiMsg(
571 "<strong>$1</strong>\n$2", $this->typeLabels['text'],
572 'revdelete-text-others'
573 );
574
575 if ( $this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' ) ) {
576 $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
577 }
578
579 if ( $this->mIsAllowed ) {
580 $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
581 }
582 }
583
587 protected function buildCheckBoxes() {
588 $fields = [];
589
590 $type = 'radio';
591
592 $list = $this->getList();
593
594 // If there is just one item, use checkboxes
595 if ( $list->length() == 1 ) {
596 $list->reset();
597
598 $type = 'check';
599 }
600
601 foreach ( $this->checks as $item ) {
602 // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
603 // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
604 [ $message, $name, $bitField ] = $item;
605
606 $field = [
607 'type' => $type,
608 'label-raw' => $this->msg( $message )->escaped(),
609 'id' => $name,
610 'flatlist' => true,
611 'name' => $name,
612 'default' => $list->length() == 1 ? $list->current()->getBits() & $bitField : null
613 ];
614
615 if ( $bitField == RevisionRecord::DELETED_RESTRICTED ) {
616 $field['label-raw'] = "<b>" . $field['label-raw'] . "</b>";
617 if ( $type === 'radio' ) {
618 $field['options-messages'] = [
619 'revdelete-radio-same' => -1,
620 'revdelete-radio-unset-suppress' => 0,
621 'revdelete-radio-set-suppress' => 1
622 ];
623 }
624 } elseif ( $type === 'radio' ) {
625 $field['options-messages'] = [
626 'revdelete-radio-same' => -1,
627 'revdelete-radio-unset' => 0,
628 'revdelete-radio-set' => 1
629 ];
630 }
631
632 $fields[] = $field;
633 }
634
635 return $fields;
636 }
637
643 protected function submit() {
644 # Check edit token on submission
645 $token = $this->getRequest()->getVal( 'wpEditToken' );
646 if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
647 $this->getOutput()->addWikiMsg( 'sessionfailure' );
648
649 return false;
650 }
651 $bitParams = $this->extractBitParams();
652 // from dropdown
653 $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
654 $comment = $listReason;
655 if ( $comment === 'other' ) {
656 $comment = $this->otherReason;
657 } elseif ( $this->otherReason !== '' ) {
658 // Entry from drop down menu + additional comment
659 $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
660 . $this->otherReason;
661 }
662 # Can the user set this field?
663 if ( $bitParams[RevisionRecord::DELETED_RESTRICTED] == 1
664 && !$this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' )
665 ) {
666 throw new PermissionsError( 'suppressrevision' );
667 }
668 # If the save went through, go to success message...
669 $status = $this->save( $bitParams, $comment );
670 if ( $status->isGood() ) {
671 $this->success();
672
673 return true;
674 } else {
675 # ...otherwise, bounce back to form...
676 $this->failure( $status );
677 }
678
679 return false;
680 }
681
685 protected function success() {
686 // Messages: revdelete-success, logdelete-success
687 $out = $this->getOutput();
688 $out->setPageTitleMsg( $this->msg( 'actioncomplete' ) );
689 $out->addHTML(
690 Html::successBox(
691 $out->msg( $this->typeLabels['success'] )->parse()
692 )
693 );
694 $this->wasSaved = true;
695 $this->revDelList->reloadFromPrimary();
696 $this->showForm();
697 }
698
703 protected function failure( $status ) {
704 // Messages: revdelete-failure, logdelete-failure
705 $out = $this->getOutput();
706 $out->setPageTitleMsg( $this->msg( 'actionfailed' ) );
707 $out->addHTML(
708 Html::errorBox(
709 $out->parseAsContent(
710 $status->getWikiText( $this->typeLabels['failure'], false, $this->getLanguage() )
711 )
712 )
713 );
714 $this->showForm();
715 }
716
722 protected function extractBitParams() {
723 $bitfield = [];
724 foreach ( $this->checks as [ /* message */, $name, $field ] ) {
725 $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
726 if ( $val < -1 || $val > 1 ) {
727 $val = -1; // -1 for existing value
728 }
729 $bitfield[$field] = $val;
730 }
731 if ( !isset( $bitfield[RevisionRecord::DELETED_RESTRICTED] ) ) {
732 $bitfield[RevisionRecord::DELETED_RESTRICTED] = 0;
733 }
734
735 return $bitfield;
736 }
737
744 protected function save( array $bitPars, $reason ) {
745 return $this->getList()->setVisibility(
746 [ 'value' => $bitPars, 'comment' => $reason ]
747 );
748 }
749
750 protected function getGroupName() {
751 return 'pagetools';
752 }
753}
754
759class_alias( SpecialRevisionDelete::class, 'SpecialRevisionDelete' );
An error page which can definitely be safely rendered using the OutputPage.
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:74
Class to simplify the use of log pages.
Definition LogPage.php:45
Handle database storage of comments such as edit summaries and log reasons.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:208
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
static submitButton( $contents, array $attrs=[], array $modifiers=[])
Returns an HTML input element in a string.
Definition Html.php:163
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 this special page may perform database writes.
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:79
Module of static functions for generating XML.
Definition Xml.php:37
Show an error when a user tries to do something they do not have the necessary permissions for.
Prioritized list of file repositories.
Definition RepoGroup.php:30
General controller for RevDel, used by both SpecialRevisiondelete and ApiRevisionDelete.
Show an error when the user tries to do something whilst blocked.