MediaWiki  master
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 ) {
138  $this->useTransactionalTimeLimit();
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" );
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" );
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(
291  SpecialPage::getTitleFor( 'Log' ),
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.misc-authed-ooui' ] );
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'] = [
612  $this->msg( 'revdelete-radio-same' )->text() => -1,
613  $this->msg( 'revdelete-radio-unset-suppress' )->text() => 0,
614  $this->msg( 'revdelete-radio-set-suppress' )->text() => 1
615  ];
616  }
617  } elseif ( $type === 'radio' ) {
618  $field['options'] = [
619  $this->msg( 'revdelete-radio-same' )->text() => -1,
620  $this->msg( 'revdelete-radio-unset' )->text() => 0,
621  $this->msg( 'revdelete-radio-set' )->text() => 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.
const DELETED_RESTRICTED
Definition: File.php:75
const DELETED_FILE
Definition: File.php:72
static factory( $displayFormat, $descriptor, IContextSource $context, $messagePrefix='')
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:352
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
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...
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.
static listDropDownOptions( $list, $params=[])
Build options for a drop-down box from a textual list.
Definition: Xml.php:548
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:113
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Definition: Xml.php:467
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:135
if(!isset( $args[0])) $lang