57 private $mTargetTimestamp = [];
61 private $mComment =
'';
72 private $mFileVersions = [];
74 private $mUndeleteTalk;
81 private $mSearchPrefix;
84 private $permissionManager;
87 private $revisionStore;
90 private $revisionRenderer;
93 private $contentHandlerFactory;
96 private $changeTagDefStore;
99 private $linkBatchFactory;
105 private $loadBalancer;
108 private $userOptionsLookup;
111 private $wikiPageFactory;
114 private $searchEngineFactory;
117 private $undeletePageFactory;
120 private $archivedRevisionLookup;
152 parent::__construct(
'Undelete',
'deletedhistory' );
153 $this->permissionManager = $permissionManager;
154 $this->revisionStore = $revisionStore;
155 $this->revisionRenderer = $revisionRenderer;
156 $this->contentHandlerFactory = $contentHandlerFactory;
157 $this->changeTagDefStore = $changeTagDefStore;
158 $this->linkBatchFactory = $linkBatchFactory;
160 $this->loadBalancer = $loadBalancer;
161 $this->userOptionsLookup = $userOptionsLookup;
162 $this->wikiPageFactory = $wikiPageFactory;
163 $this->searchEngineFactory = $searchEngineFactory;
164 $this->undeletePageFactory = $undeletePageFactory;
165 $this->archivedRevisionLookup = $archivedRevisionLookup;
172 private function loadRequest( $par ) {
176 $this->mAction = $request->getRawVal(
'action' );
177 if ( $par !==
null && $par !==
'' ) {
178 $this->mTarget = $par;
180 $this->mTarget = $request->getVal(
'target' );
183 $this->mTargetObj =
null;
185 if ( $this->mTarget !==
null && $this->mTarget !==
'' ) {
189 $this->mSearchPrefix = $request->getText(
'prefix' );
190 $time = $request->getVal(
'timestamp' );
191 $this->mTimestamp = $time ?
wfTimestamp( TS_MW, $time ) :
'';
192 $this->mFilename = $request->getVal(
'file' );
194 $posted = $request->wasPosted() &&
195 $user->matchEditToken( $request->getVal(
'wpEditToken' ) );
196 $this->mRestore = $request->getCheck(
'restore' ) && $posted;
197 $this->mRevdel = $request->getCheck(
'revdel' ) && $posted;
198 $this->mInvert = $request->getCheck(
'invert' ) && $posted;
199 $this->mPreview = $request->getCheck(
'preview' ) && $posted;
200 $this->mDiff = $request->getCheck(
'diff' );
201 $this->mDiffOnly = $request->getBool(
'diffonly',
202 $this->userOptionsLookup->getOption( $this->getUser(),
'diffonly' ) );
203 $this->mComment = $request->getText(
'wpComment' );
204 $this->mUnsuppress = $request->getVal(
'wpUnsuppress' ) &&
205 $this->permissionManager->userHasRight( $user,
'suppressrevision' );
206 $this->mToken = $request->getVal(
'token' );
207 $this->mUndeleteTalk = $request->getCheck(
'undeletetalk' );
210 $this->mAllowed =
true;
211 $this->mCanView =
true;
212 } elseif ( $this->
isAllowed(
'deletedtext' ) ) {
213 $this->mAllowed =
false;
214 $this->mCanView =
true;
215 $this->mRestore =
false;
217 $this->mAllowed =
false;
218 $this->mCanView =
false;
219 $this->mTimestamp =
'';
220 $this->mRestore =
false;
223 if ( $this->mRestore || $this->mInvert ) {
225 $this->mFileVersions = [];
226 foreach ( $request->getValues() as $key => $val ) {
228 if ( preg_match(
'/^ts(\d{14})$/', $key,
$matches ) ) {
229 array_push( $timestamps,
$matches[1] );
232 if ( preg_match(
'/^fileid(\d+)$/', $key,
$matches ) ) {
233 $this->mFileVersions[] = intval(
$matches[1] );
236 rsort( $timestamps );
237 $this->mTargetTimestamp = $timestamps;
250 $user = $user ?: $this->
getUser();
251 $block = $user->getBlock();
253 if ( $this->mTargetObj !==
null ) {
254 return $this->permissionManager->userCan( $permission, $user, $this->mTargetObj );
256 $hasRight = $this->permissionManager->userHasRight( $user, $permission );
257 $sitewideBlock = $block && $block->isSitewide();
258 return $permission ===
'undelete' ? ( $hasRight && !$sitewideBlock ) : $hasRight;
263 return $this->
isAllowed( $this->mRestriction, $user );
274 if ( !parent::userCanExecute( $user ) ) {
281 $this->mTargetObj && $this->permissionManager->isBlockedFrom( $user, $this->mTargetObj ) ) {
299 $this->
addHelpLink(
'Help:Deletion_and_undeletion' );
301 $this->loadRequest( $par );
306 if ( $this->mTargetObj ===
null ) {
307 $out->addWikiMsg(
'undelete-header' );
309 # Not all users can just browse every deleted page from the list
310 if ( $this->permissionManager->userHasRight( $user,
'browsearchive' ) ) {
311 $this->showSearchForm();
318 if ( $this->mAllowed ) {
319 $out->setPageTitle( $this->
msg(
'undeletepage' ) );
321 $out->setPageTitle( $this->
msg(
'viewdeletedpage' ) );
324 $this->
getSkin()->setRelevantTitle( $this->mTargetObj );
326 if ( $this->mTimestamp !==
'' ) {
327 $this->showRevision( $this->mTimestamp );
328 } elseif ( $this->mFilename !==
null && $this->mTargetObj->inNamespace(
NS_FILE ) ) {
331 if ( !
$file->exists() ) {
332 $out->addWikiMsg(
'filedelete-nofile', $this->mFilename );
333 } elseif ( !
$file->userCan( File::DELETED_FILE, $user ) ) {
334 if (
$file->isDeleted( File::DELETED_RESTRICTED ) ) {
339 } elseif ( !$user->matchEditToken( $this->mToken, $this->mFilename ) ) {
340 $this->showFileConfirmationForm( $this->mFilename );
342 $this->showFile( $this->mFilename );
344 } elseif ( $this->mAction ===
'submit' ) {
345 if ( $this->mRestore ) {
347 } elseif ( $this->mRevdel ) {
348 $this->redirectToRevDel();
360 private function redirectToRevDel() {
363 foreach ( $this->
getRequest()->getValues() as $key => $val ) {
365 if ( preg_match(
"/^ts(\d{14})$/", $key,
$matches ) ) {
366 $revisionRecord = $this->archivedRevisionLookup
367 ->getRevisionRecordByTimestamp( $this->mTargetObj,
$matches[1] );
368 if ( $revisionRecord ) {
370 $revisions[ $revisionRecord->getId() ] = 1;
376 'type' =>
'revision',
378 'target' => $this->mTargetObj->getPrefixedText()
384 private function showSearchForm() {
386 $out->setPageTitle( $this->
msg(
'undelete-search-title' ) );
387 $fuzzySearch = $this->
getRequest()->getVal(
'fuzzy',
'1' );
392 $fields[] =
new OOUI\ActionFieldLayout(
393 new OOUI\TextInputWidget( [
395 'inputId' =>
'prefix',
397 'value' => $this->mSearchPrefix,
400 new OOUI\ButtonInputWidget( [
401 'label' => $this->
msg(
'undelete-search-submit' )->text(),
402 'flags' => [
'primary',
'progressive' ],
403 'inputId' =>
'searchUndelete',
407 'label' =>
new OOUI\HtmlSnippet(
409 $fuzzySearch ?
'undelete-search-full' :
'undelete-search-prefix'
416 $fieldset =
new OOUI\FieldsetLayout( [
417 'label' => $this->
msg(
'undelete-search-box' )->text(),
421 $form =
new OOUI\FormLayout( [
426 $form->appendContent(
428 new OOUI\HtmlSnippet(
429 Html::hidden(
'title', $this->
getPageTitle()->getPrefixedDBkey() ) .
430 Html::hidden(
'fuzzy', $fuzzySearch )
435 new OOUI\PanelLayout( [
443 # List undeletable articles
444 if ( $this->mSearchPrefix ) {
447 if ( $fuzzySearch ) {
452 $this->showList( $result );
462 private function showList( $result ) {
465 if ( $result->numRows() == 0 ) {
466 $out->addWikiMsg(
'undelete-no-results' );
471 $out->addWikiMsg(
'undeletepagetext', $this->
getLanguage()->formatNum( $result->numRows() ) );
475 $out->addHTML(
"<ul id='undeleteResultsList'>\n" );
476 foreach ( $result as $row ) {
479 $item = $linkRenderer->makeKnownLink(
481 $title->getPrefixedText(),
483 [
'target' =>
$title->getPrefixedText() ]
489 [
'class' =>
'mw-invalidtitle' ],
497 $revs = $this->
msg(
'undeleterevisions' )->numParams( $row->count )->parse();
501 [
'class' =>
'undeleteResult' ],
507 $out->addHTML(
"</ul>\n" );
512 private function showRevision( $timestamp ) {
513 if ( !preg_match(
'/[0-9]{14}/', $timestamp ) ) {
522 $this->
msg(
'undelete-back-to-list' )->text(),
524 [
'target' => $this->mTargetObj->getPrefixedText() ]
527 $subtitle =
"< $listLink";
528 $out->setSubtitle( $subtitle );
533 $archive, $this->mTargetObj )
537 $revRecord = $this->archivedRevisionLookup->getRevisionRecordByTimestamp( $this->mTargetObj, $timestamp );
542 $out->addWikiMsg(
'undeleterevision-missing' );
546 if ( $revRecord->
isDeleted( RevisionRecord::DELETED_TEXT ) ) {
548 $titleText = $this->mTargetObj->getPrefixedDBkey();
549 if ( !$revRecord->
userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
550 $msg = $revRecord->
isDeleted( RevisionRecord::DELETED_RESTRICTED )
551 ? [
'rev-suppressed-text-permission', $titleText ]
552 : [
'rev-deleted-text-permission', $titleText ];
555 $this->
msg( $msg[0], $msg[1] )->parse(),
562 $msg = $revRecord->
isDeleted( RevisionRecord::DELETED_RESTRICTED )
563 ? [
'rev-suppressed-text-view', $titleText ]
564 : [
'rev-deleted-text-view', $titleText ];
567 $this->
msg( $msg[0], $msg[1] )->parse(),
574 if ( $this->mDiff ) {
575 $previousRevRecord = $this->archivedRevisionLookup
576 ->getPreviousRevisionRecord( $this->mTargetObj, $timestamp );
577 if ( $previousRevRecord ) {
578 $this->showDiff( $previousRevRecord, $revRecord );
579 if ( $this->mDiffOnly ) {
583 $out->addHTML(
'<hr />' );
585 $out->addWikiMsg(
'undelete-nodiff' );
590 $this->
getPageTitle( $this->mTargetObj->getPrefixedDBkey() ),
591 $this->mTargetObj->getPrefixedText()
598 $time =
$lang->userTimeAndDate( $timestamp, $user );
599 $d =
$lang->userDate( $timestamp, $user );
600 $t =
$lang->userTime( $timestamp, $user );
605 RevisionRecord::FOR_THIS_USER,
612 $undeleteRevisionContent =
'';
614 if ( !$this->mDiff ) {
621 $undeleteRevisionContent = $revdel .
' ';
625 $undeleteRevisionContent .= $out->msg(
634 if ( $this->mPreview || $isText ) {
637 $undeleteRevisionContent,
638 'mw-undelete-revision'
645 [
'class' =>
'mw-undelete-revision', ],
646 $undeleteRevisionContent
651 if ( $this->mPreview || !$isText ) {
654 $popts = $out->parserOptions();
656 $rendered = $this->revisionRenderer->getRenderedRevision(
660 [
'audience' => RevisionRecord::FOR_THIS_USER ]
665 $pout = $rendered->getRevisionParserOutput();
667 $out->addParserOutput( $pout, [
668 'enableSectionEditLinks' =>
false,
676 '@phan-var TextContent $content';
680 'readonly' =>
'readonly',
685 $buttonFields[] =
new OOUI\ButtonInputWidget( [
688 'label' => $this->
msg(
'showpreview' )->text()
694 $buttonFields[] =
new OOUI\ButtonInputWidget( [
697 'label' => $this->
msg(
'showdiff' )->text()
702 Xml::openElement(
'div', [
703 'style' =>
'clear: both' ] ) .
704 Xml::openElement(
'form', [
706 'action' => $this->
getPageTitle()->getLocalURL( [
'action' =>
'submit' ] ) ] ) .
707 Xml::element(
'input', [
710 'value' => $this->mTargetObj->getPrefixedDBkey() ] ) .
711 Xml::element(
'input', [
713 'name' =>
'timestamp',
714 'value' => $timestamp ] ) .
715 Xml::element(
'input', [
717 'name' =>
'wpEditToken',
718 'value' => $user->getEditToken() ] ) .
719 new OOUI\FieldLayout(
721 'content' =>
new OOUI\HorizontalLayout( [
722 'items' => $buttonFields
726 Xml::closeElement(
'form' ) .
727 Xml::closeElement(
'div' )
738 private function showDiff(
745 $diffContext->setTitle( $currentTitle );
746 $diffContext->setWikiPage( $this->wikiPageFactory->newFromTitle( $currentTitle ) );
748 $contentModel = $currentRevRecord->
getSlot(
753 $diffEngine = $this->contentHandlerFactory->getContentHandler( $contentModel )
754 ->createDifferenceEngine( $diffContext );
756 $diffEngine->setRevisions( $previousRevRecord, $currentRevRecord );
757 $diffEngine->showDiffStyle();
758 $formattedDiff = $diffEngine->getDiff(
759 $this->diffHeader( $previousRevRecord,
'o' ),
760 $this->diffHeader( $currentRevRecord,
'n' )
763 $this->
getOutput()->addHTML(
"<div>$formattedDiff</div>\n" );
771 private function diffHeader(
RevisionRecord $revRecord, $prefix ) {
777 'target' => $this->mTargetObj->getPrefixedText(),
783 $targetQuery = [
'oldid' => $revRecord->
getId() ];
797 $dbr = $this->loadBalancer->getConnectionRef( ILoadBalancer::DB_REPLICA );
798 $tagIds =
$dbr->selectFieldValues(
801 [
'ct_rev_id' => $revRecord->
getId() ],
805 foreach ( $tagIds as $tagId ) {
807 $tags[] = $this->changeTagDefStore->getName( (
int)$tagId );
812 $tags = implode(
',', $tags );
817 return '<div id="mw-diff-' . $prefix .
'title1"><strong>' .
830 '<div id="mw-diff-' . $prefix .
'title2">' .
833 '<div id="mw-diff-' . $prefix .
'title3">' .
836 '<div id="mw-diff-' . $prefix .
'title5">' .
837 $tagSummary[0] .
'<br />' .
845 private function showFileConfirmationForm( $key ) {
850 $out->addWikiMsg(
'undelete-show-file-confirm',
851 $this->mTargetObj->getText(),
852 $lang->userDate(
$file->getTimestamp(), $user ),
853 $lang->userTime(
$file->getTimestamp(), $user ) );
855 Xml::openElement(
'form', [
858 'target' => $this->mTarget,
860 'token' => $user->getEditToken( $key ),
864 Xml::submitButton( $this->msg(
'undelete-show-file-submit' )->text() ) .
873 private function showFile( $key ) {
876 # We mustn't allow the output to be CDN cached, otherwise
877 # if an admin previews a deleted image, and it's cached, then
878 # a user without appropriate permissions can toddle off and
879 # nab the image, and CDN will serve it
881 $response->header(
'Expires: ' . gmdate(
'D, d M Y H:i:s', 0 ) .
' GMT' );
882 $response->header(
'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
883 $response->header(
'Pragma: no-cache' );
885 $path = $this->localRepo->getZonePath(
'deleted' ) .
'/' . $this->localRepo->getDeletedHashPath( $key ) . $key;
886 $this->localRepo->streamFileWithStatus(
$path );
893 if ( $this->mAllowed ) {
894 $out->addModules(
'mediawiki.misc-authed-ooui' );
897 "<div class='mw-undelete-pagetitle'>\n$1\n</div>\n",
898 [
'undeletepagetitle',
wfEscapeWikiText( $this->mTargetObj->getPrefixedText() ) ]
903 $this->
getHookRunner()->onUndeleteForm__showHistory( $archive, $this->mTargetObj );
905 $out->addHTML( Html::openElement(
'div', [
'class' =>
'mw-undelete-history' ] ) );
906 if ( $this->mAllowed ) {
907 $out->addWikiMsg(
'undeletehistory' );
908 $out->addWikiMsg(
'undeleterevdel' );
910 $out->addWikiMsg(
'undeletehistorynoadmin' );
912 $out->addHTML( Html::closeElement(
'div' ) );
914 # List all stored revisions
915 $revisions = $this->archivedRevisionLookup->listRevisions( $this->mTargetObj );
916 $files = $archive->listFiles();
918 $haveRevisions = $revisions && $revisions->numRows() > 0;
919 $haveFiles = $files && $files->numRows() > 0;
921 # Batch existence check on user and talk pages
922 if ( $haveRevisions || $haveFiles ) {
923 $batch = $this->linkBatchFactory->newLinkBatch();
924 if ( $haveRevisions ) {
925 foreach ( $revisions as $row ) {
926 $batch->add(
NS_USER, $row->ar_user_text );
929 $revisions->seek( 0 );
932 foreach ( $files as $row ) {
933 $batch->add(
NS_USER, $row->fa_user_text );
941 if ( $this->mAllowed ) {
944 $action = $this->
getPageTitle()->getLocalURL( [
'action' =>
'submit' ] );
945 # Start the form here
946 $form =
new OOUI\FormLayout( [
953 # Show relevant lines from the deletion log:
954 $deleteLogPage =
new LogPage(
'delete' );
955 $out->addHTML( Xml::element(
'h2',
null, $deleteLogPage->getName()->text() ) .
"\n" );
956 LogEventsList::showLogExtract( $out,
'delete', $this->mTargetObj );
957 # Show relevant lines from the suppression log:
958 $suppressLogPage =
new LogPage(
'suppress' );
959 if ( $this->permissionManager->userHasRight( $this->getUser(),
'suppressionlog' ) ) {
960 $out->addHTML( Xml::element(
'h2',
null, $suppressLogPage->getName()->text() ) .
"\n" );
961 LogEventsList::showLogExtract( $out,
'suppress', $this->mTargetObj );
964 if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
966 $fields[] =
new OOUI\Layout( [
967 'content' =>
new OOUI\HtmlSnippet( $this->
msg(
'undeleteextrahelp' )->parseAsBlock() )
970 $fields[] =
new OOUI\FieldLayout(
971 new OOUI\TextInputWidget( [
972 'name' =>
'wpComment',
973 'inputId' =>
'wpComment',
975 'value' => $this->mComment,
980 'maxLength' => CommentStore::COMMENT_CHARACTER_LIMIT,
983 'label' => $this->
msg(
'undeletecomment' )->text(),
988 if ( $this->permissionManager->userHasRight( $this->getUser(),
'suppressrevision' ) ) {
989 $fields[] =
new OOUI\FieldLayout(
990 new OOUI\CheckboxInputWidget( [
991 'name' =>
'wpUnsuppress',
992 'inputId' =>
'mw-undelete-unsuppress',
996 'label' => $this->
msg(
'revdelete-unsuppress' )->text(),
1002 $undelPage = $this->undeletePageFactory->newUndeletePage(
1003 $this->wikiPageFactory->newFromTitle( $this->mTargetObj ),
1004 $this->getContext()->getAuthority()
1006 if ( $undelPage->canProbablyUndeleteAssociatedTalk()->isGood() ) {
1007 $fields[] =
new OOUI\FieldLayout(
1008 new OOUI\CheckboxInputWidget( [
1009 'name' =>
'undeletetalk',
1010 'inputId' =>
'mw-undelete-undeletetalk',
1011 'selected' =>
false,
1014 'label' => $this->
msg(
'undelete-undeletetalk' )->text(),
1015 'align' =>
'inline',
1020 $fields[] =
new OOUI\FieldLayout(
1022 'content' =>
new OOUI\HorizontalLayout( [
1024 new OOUI\ButtonInputWidget( [
1025 'name' =>
'restore',
1026 'inputId' =>
'mw-undelete-submit',
1028 'label' => $this->
msg(
'undeletebtn' )->text(),
1029 'flags' => [
'primary',
'progressive' ],
1032 new OOUI\ButtonInputWidget( [
1034 'inputId' =>
'mw-undelete-invert',
1036 'label' => $this->
msg(
'undeleteinvert' )->text()
1043 $fieldset =
new OOUI\FieldsetLayout( [
1044 'label' => $this->
msg(
'undelete-fieldset-title' )->text(),
1045 'id' =>
'mw-undelete-table',
1050 $form->appendContent(
1051 new OOUI\PanelLayout( [
1052 'expanded' =>
false,
1055 'content' => $fieldset,
1057 new OOUI\HtmlSnippet(
1058 Html::hidden(
'target', $this->mTarget ) .
1059 Html::hidden(
'wpEditToken', $this->
getUser()->getEditToken() )
1065 $history .= Xml::element(
'h2',
null, $this->
msg(
'history' )->text() ) .
"\n";
1067 if ( $haveRevisions ) {
1068 # Show the page's stored (deleted) history
1070 if ( $this->permissionManager->userHasRight( $this->getUser(),
'deleterevision' ) ) {
1071 $history .= Html::element(
1076 'class' =>
'deleterevision-log-submit mw-log-deleterevision-button'
1078 $this->
msg(
'showhideselectedversions' )->text()
1082 $history .= Html::openElement(
'ul', [
'class' =>
'mw-undelete-revlist' ] );
1083 $remaining = $revisions->numRows();
1084 $firstRev = $this->revisionStore->getFirstRevision( $this->mTargetObj );
1085 $earliestLiveTime = $firstRev ? $firstRev->getTimestamp() :
null;
1087 foreach ( $revisions as $row ) {
1092 $history .= Html::closeElement(
'ul' );
1094 $out->addWikiMsg(
'nohistory' );
1098 $history .= Xml::element(
'h2',
null, $this->
msg(
'filehist' )->text() ) .
"\n";
1099 $history .= Html::openElement(
'ul', [
'class' =>
'mw-undelete-revlist' ] );
1100 foreach ( $files as $row ) {
1101 $history .= $this->formatFileRow( $row );
1104 $history .= Html::closeElement(
'ul' );
1107 if ( $this->mAllowed ) {
1108 # Slip in the hidden controls here
1109 $misc = Html::hidden(
'target', $this->mTarget );
1110 $misc .= Html::hidden(
'wpEditToken', $this->
getUser()->getEditToken() );
1114 $form->appendContent(
new OOUI\HtmlSnippet( $history ) );
1116 $out->addHTML( (
string)$form );
1118 $out->addHTML( $history );
1125 $revRecord = $this->revisionStore->newRevisionFromArchiveRow(
1127 RevisionStore::READ_NORMAL,
1134 if ( $this->mAllowed ) {
1135 if ( $this->mInvert ) {
1136 if ( in_array( $ts, $this->mTargetTimestamp ) ) {
1137 $checkBox = Xml::check(
"ts$ts" );
1139 $checkBox = Xml::check(
"ts$ts",
true );
1142 $checkBox = Xml::check(
"ts$ts" );
1150 if ( $this->mCanView ) {
1153 if ( !$revRecord->
userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
1154 $pageLink = htmlspecialchars( $this->
getLanguage()->userTimeAndDate( $ts, $user ) );
1155 $last = $this->
msg(
'diff' )->escaped();
1156 } elseif ( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) {
1157 $pageLink = $this->getPageLink( $revRecord, $titleObj, $ts );
1160 $this->
msg(
'diff' )->text(),
1163 'target' => $this->mTargetObj->getPrefixedText(),
1169 $pageLink = $this->getPageLink( $revRecord, $titleObj, $ts );
1170 $last = $this->
msg(
'diff' )->escaped();
1173 $pageLink = htmlspecialchars( $this->
getLanguage()->userTimeAndDate( $ts, $user ) );
1174 $last = $this->
msg(
'diff' )->escaped();
1181 $minor = $revRecord->
isMinor() ? ChangesList::flag(
'minor' ) :
'';
1184 $size = $row->ar_len;
1185 if ( $size !==
null ) {
1200 $attribs[
'class'] = implode(
' ', $classes );
1203 $revisionRow = $this->
msg(
'undelete-revision-row2' )
1216 return Xml::tags(
'li', $attribs, $revisionRow ) .
"\n";
1219 private function formatFileRow( $row ) {
1225 if ( $this->mCanView && $row->fa_storage_key ) {
1226 if ( $this->mAllowed ) {
1227 $checkBox = Xml::check(
'fileid' . $row->fa_id );
1229 $key = urlencode( $row->fa_storage_key );
1232 $pageLink = htmlspecialchars( $this->
getLanguage()->userTimeAndDate( $ts, $user ) );
1234 $userLink = $this->getFileUser(
$file );
1235 $data = $this->
msg(
'widthheight' )->numParams( $row->fa_width, $row->fa_height )->text();
1236 $bytes = $this->
msg(
'parentheses' )
1237 ->plaintextParams( $this->
msg(
'nbytes' )->numParams( $row->fa_size )->text() )
1239 $data = htmlspecialchars( $data .
' ' . $bytes );
1240 $comment = $this->getFileComment(
$file );
1243 $canHide = $this->
isAllowed(
'deleterevision' );
1244 if ( $canHide || (
$file->getVisibility() && $this->isAllowed(
'deletedhistory' ) ) ) {
1245 if ( !
$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
1250 'type' =>
'filearchive',
1251 'target' => $this->mTargetObj->getPrefixedDBkey(),
1252 'ids' => $row->fa_id
1255 $file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
1261 return "<li>$checkBox $revdlink $pageLink . . $userLink $data $comment</li>\n";
1272 private function getPageLink(
RevisionRecord $revRecord, $titleObj, $ts ) {
1274 $time = $this->
getLanguage()->userTimeAndDate( $ts, $user );
1276 if ( !$revRecord->
userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
1281 [
'class' =>
'history-deleted' ],
1282 htmlspecialchars( $time )
1291 'target' => $this->mTargetObj->getPrefixedText(),
1296 if ( $revRecord->
isDeleted( RevisionRecord::DELETED_TEXT ) ) {
1298 $link =
'<span class="' . $class .
'">' . $link .
'</span>';
1314 private function getFileLink(
$file, $titleObj, $ts, $key ) {
1316 $time = $this->
getLanguage()->userTimeAndDate( $ts, $user );
1318 if ( !
$file->userCan( File::DELETED_FILE, $user ) ) {
1322 [
'class' =>
'history-deleted' ],
1323 htmlspecialchars( $time )
1332 'target' => $this->mTargetObj->getPrefixedText(),
1334 'token' => $user->getEditToken( $key )
1338 if (
$file->isDeleted( File::DELETED_FILE ) ) {
1339 $link =
'<span class="history-deleted">' . $link .
'</span>';
1351 private function getFileUser(
$file ) {
1356 [
'class' =>
'history-deleted' ],
1357 $this->
msg(
'rev-deleted-user' )->escaped()
1364 if (
$file->isDeleted( File::DELETED_USER ) ) {
1367 [
'class' =>
'history-deleted' ],
1381 private function getFileComment(
$file ) {
1382 if ( !
$file->userCan( File::DELETED_COMMENT, $this->getAuthority() ) ) {
1385 [
'class' =>
'history-deleted' ],
1388 [
'class' =>
'comment' ],
1389 $this->
msg(
'rev-deleted-comment' )->escaped()
1397 if (
$file->isDeleted( File::DELETED_COMMENT ) ) {
1400 [
'class' =>
'history-deleted' ],
1408 private function undelete() {
1409 if ( $this->
getConfig()->
get( MainConfigNames::UploadMaintenance )
1410 && $this->mTargetObj->getNamespace() ===
NS_FILE
1412 throw new ErrorPageError(
'undelete-error',
'filedelete-maintenance' );
1418 $undeletePage = $this->undeletePageFactory->newUndeletePage(
1419 $this->wikiPageFactory->newFromTitle( $this->mTargetObj ),
1420 $this->getAuthority()
1422 if ( $this->mUndeleteTalk && $undeletePage->canProbablyUndeleteAssociatedTalk()->isGood() ) {
1423 $undeletePage->setUndeleteAssociatedTalk(
true );
1425 $status = $undeletePage
1426 ->setUndeleteOnlyTimestamps( $this->mTargetTimestamp )
1427 ->setUndeleteOnlyFileVersions( $this->mFileVersions )
1428 ->setUnsuppress( $this->mUnsuppress )
1430 ->undeleteIfAllowed( $this->mComment );
1432 if ( !$status->isGood() ) {
1433 $out->setPageTitle( $this->
msg(
'undelete-error' ) );
1434 $out->wrapWikiTextAsInterface(
1436 Status::wrap( $status )->getWikiText(
1445 $restoredRevs = $status->getValue()[UndeletePage::REVISIONS_RESTORED];
1446 $restoredFiles = $status->getValue()[UndeletePage::FILES_RESTORED];
1448 if ( $restoredRevs === 0 && $restoredFiles === 0 ) {
1450 $out->setPageTitle( $this->
msg(
'undelete-error' ) );
1452 if ( $status->getValue()[UndeletePage::FILES_RESTORED] !== 0 ) {
1454 $this->mTargetObj, $this->mFileVersions, $this->
getUser(), $this->mComment );
1471 return $this->
prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );