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