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