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