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' )->inContentLanguage()->text();
478 // Add additional specific reasons for suppress
479 if ( $suppressAllowed ) {
480 $dropDownReason .= "\n" . $this->msg( 'revdelete-reason-dropdown-suppress' )
481 ->inContentLanguage()->text();
482 }
483
484 $fields = $this->buildCheckBoxes();
485
486 $fields[] = [
487 'type' => 'select',
488 'label' => $this->msg( 'revdelete-log' )->text(),
489 'cssclass' => 'wpReasonDropDown',
490 'id' => 'wpRevDeleteReasonList',
491 'name' => 'wpRevDeleteReasonList',
492 'options' => Html::listDropDownOptions(
493 $dropDownReason,
494 [ 'other' => $this->msg( 'revdelete-reasonotherlist' )->text() ]
495 ),
496 'default' => $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' )
497 ];
498
499 $fields[] = [
500 'type' => 'text',
501 'label' => $this->msg( 'revdelete-otherreason' )->text(),
502 'name' => 'wpReason',
503 'id' => 'wpReason',
504 // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
505 // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
506 // Unicode codepoints.
507 // "- 155" is to leave room for the 'wpRevDeleteReasonList' value.
508 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT - 155,
509 ];
510
511 $fields[] = [
512 'type' => 'hidden',
513 'name' => 'wpEditToken',
514 'default' => $this->getUser()->getEditToken()
515 ];
516
517 $fields[] = [
518 'type' => 'hidden',
519 'name' => 'target',
520 'default' => $this->targetObj->getPrefixedText()
521 ];
522
523 $fields[] = [
524 'type' => 'hidden',
525 'name' => 'type',
526 'default' => $this->typeName
527 ];
528
529 $fields[] = [
530 'type' => 'hidden',
531 'name' => 'ids',
532 'default' => implode( ',', $this->ids )
533 ];
534
535 $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
536 $htmlForm
537 ->setSubmitText( $this->msg( 'revdelete-submit', $numRevisions )->text() )
538 ->setSubmitName( 'wpSubmit' )
539 ->setWrapperLegend( $this->msg( 'revdelete-legend' )->text() )
540 ->setAction( $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ) )
541 ->loadData();
542 // Show link to edit the dropdown reasons
543 if ( $this->permissionManager->userHasRight( $this->getUser(), 'editinterface' ) ) {
544 $link = '';
545 $linkRenderer = $this->getLinkRenderer();
546 if ( $suppressAllowed ) {
547 $link .= $linkRenderer->makeKnownLink(
548 $this->msg( 'revdelete-reason-dropdown-suppress' )->inContentLanguage()->getTitle(),
549 $this->msg( 'revdelete-edit-reasonlist-suppress' )->text(),
550 [],
551 [ 'action' => 'edit' ]
552 );
553 $link .= $this->msg( 'pipe-separator' )->escaped();
554 }
555 $link .= $linkRenderer->makeKnownLink(
556 $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
557 $this->msg( 'revdelete-edit-reasonlist' )->text(),
558 [],
559 [ 'action' => 'edit' ]
560 );
561 $htmlForm->setPostHtml( Xml::tags( 'p', [ 'class' => 'mw-revdel-editreasons' ], $link ) );
562 }
563 $out->addHTML( $htmlForm->getHTML( false ) );
564 }
565 }
566
571 protected function addUsageText() {
572 // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
573 $this->getOutput()->wrapWikiMsg(
574 "<strong>$1</strong>\n$2", $this->typeLabels['text'],
575 'revdelete-text-others'
576 );
577
578 if ( $this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' ) ) {
579 $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
580 }
581
582 if ( $this->mIsAllowed ) {
583 $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
584 }
585 }
586
590 protected function buildCheckBoxes() {
591 $fields = [];
592
593 $type = 'radio';
594
595 $list = $this->getList();
596
597 // If there is just one item, use checkboxes
598 if ( $list->length() == 1 ) {
599 $list->reset();
600
601 $type = 'check';
602 }
603
604 foreach ( $this->checks as $item ) {
605 // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
606 // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
607 [ $message, $name, $bitField ] = $item;
608
609 $field = [
610 'type' => $type,
611 'label-raw' => $this->msg( $message )->escaped(),
612 'id' => $name,
613 'flatlist' => true,
614 'name' => $name,
615 'default' => $list->length() == 1 ? $list->current()->getBits() & $bitField : null
616 ];
617
618 if ( $bitField == RevisionRecord::DELETED_RESTRICTED ) {
619 $field['label-raw'] = "<b>" . $field['label-raw'] . "</b>";
620 if ( $type === 'radio' ) {
621 $field['options-messages'] = [
622 'revdelete-radio-same' => -1,
623 'revdelete-radio-unset-suppress' => 0,
624 'revdelete-radio-set-suppress' => 1
625 ];
626 }
627 } elseif ( $type === 'radio' ) {
628 $field['options-messages'] = [
629 'revdelete-radio-same' => -1,
630 'revdelete-radio-unset' => 0,
631 'revdelete-radio-set' => 1
632 ];
633 }
634
635 $fields[] = $field;
636 }
637
638 return $fields;
639 }
640
646 protected function submit() {
647 # Check edit token on submission
648 $token = $this->getRequest()->getVal( 'wpEditToken' );
649 if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
650 $this->getOutput()->addWikiMsg( 'sessionfailure' );
651
652 return false;
653 }
654 $bitParams = $this->extractBitParams();
655 // from dropdown
656 $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
657 $comment = $listReason;
658 if ( $comment === 'other' ) {
659 $comment = $this->otherReason;
660 } elseif ( $this->otherReason !== '' ) {
661 // Entry from drop down menu + additional comment
662 $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
663 . $this->otherReason;
664 }
665 # Can the user set this field?
666 if ( $bitParams[RevisionRecord::DELETED_RESTRICTED] == 1
667 && !$this->permissionManager->userHasRight( $this->getUser(), 'suppressrevision' )
668 ) {
669 throw new PermissionsError( 'suppressrevision' );
670 }
671 # If the save went through, go to success message...
672 $status = $this->save( $bitParams, $comment );
673 if ( $status->isGood() ) {
674 $this->success();
675
676 return true;
677 } else {
678 # ...otherwise, bounce back to form...
679 $this->failure( $status );
680 }
681
682 return false;
683 }
684
688 protected function success() {
689 // Messages: revdelete-success, logdelete-success
690 $out = $this->getOutput();
691 $out->setPageTitleMsg( $this->msg( 'actioncomplete' ) );
692 $out->addHTML(
693 Html::successBox(
694 $out->msg( $this->typeLabels['success'] )->parse()
695 )
696 );
697 $this->wasSaved = true;
698 $this->revDelList->reloadFromPrimary();
699 $this->showForm();
700 }
701
706 protected function failure( $status ) {
707 // Messages: revdelete-failure, logdelete-failure
708 $out = $this->getOutput();
709 $out->setPageTitleMsg( $this->msg( 'actionfailed' ) );
710 $out->addHTML(
711 Html::errorBox(
712 $out->parseAsContent(
713 $status->getWikiText( $this->typeLabels['failure'], false, $this->getLanguage() )
714 )
715 )
716 );
717 $this->showForm();
718 }
719
725 protected function extractBitParams() {
726 $bitfield = [];
727 foreach ( $this->checks as [ /* message */, $name, $field ] ) {
728 $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
729 if ( $val < -1 || $val > 1 ) {
730 $val = -1; // -1 for existing value
731 }
732 $bitfield[$field] = $val;
733 }
734 if ( !isset( $bitfield[RevisionRecord::DELETED_RESTRICTED] ) ) {
735 $bitfield[RevisionRecord::DELETED_RESTRICTED] = 0;
736 }
737
738 return $bitfield;
739 }
740
747 protected function save( array $bitPars, $reason ) {
748 return $this->getList()->setVisibility(
749 [ 'value' => $bitPars, 'comment' => $reason ]
750 );
751 }
752
753 protected function getGroupName() {
754 return 'pagetools';
755 }
756}
757
762class_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...