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