MediaWiki  REL1_19
FileDeleteForm.php
Go to the documentation of this file.
00001 <?php
00002 
00009 class FileDeleteForm {
00010 
00014         private $title = null;
00015 
00019         private $file = null;
00020 
00024         private $oldfile = null;
00025         private $oldimage = '';
00026 
00032         public function __construct( $file ) {
00033                 $this->title = $file->getTitle();
00034                 $this->file = $file;
00035         }
00036 
00041         public function execute() {
00042                 global $wgOut, $wgRequest, $wgUser, $wgUploadMaintenance;
00043 
00044                 $permissionErrors = $this->title->getUserPermissionsErrors( 'delete', $wgUser );
00045                 if ( count( $permissionErrors ) ) {
00046                         throw new PermissionsError( 'delete', $permissionErrors );
00047                 }
00048 
00049                 if ( wfReadOnly() ) {
00050                         throw new ReadOnlyError;
00051                 }
00052 
00053                 if ( $wgUploadMaintenance ) {
00054                         throw new ErrorPageError( 'filedelete-maintenance-title', 'filedelete-maintenance' );
00055                 }
00056 
00057                 $this->setHeaders();
00058 
00059                 $this->oldimage = $wgRequest->getText( 'oldimage', false );
00060                 $token = $wgRequest->getText( 'wpEditToken' );
00061                 # Flag to hide all contents of the archived revisions
00062                 $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed('suppressrevision');
00063 
00064                 if( $this->oldimage ) {
00065                         $this->oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->title, $this->oldimage );
00066                 }
00067 
00068                 if( !self::haveDeletableFile($this->file, $this->oldfile, $this->oldimage) ) {
00069                         $wgOut->addHTML( $this->prepareMessage( 'filedelete-nofile' ) );
00070                         $wgOut->addReturnTo( $this->title );
00071                         return;
00072                 }
00073 
00074                 // Perform the deletion if appropriate
00075                 if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) {
00076                         $deleteReasonList = $wgRequest->getText( 'wpDeleteReasonList' );
00077                         $deleteReason = $wgRequest->getText( 'wpReason' );
00078 
00079                         if ( $deleteReasonList == 'other' ) {
00080                                 $reason = $deleteReason;
00081                         } elseif ( $deleteReason != '' ) {
00082                                 // Entry from drop down menu + additional comment
00083                                 $reason = $deleteReasonList . wfMsgForContent( 'colon-separator' ) . $deleteReason;
00084                         } else {
00085                                 $reason = $deleteReasonList;
00086                         }
00087 
00088                         $status = self::doDelete( $this->title, $this->file, $this->oldimage, $reason, $suppress, $wgUser );
00089 
00090                         if( !$status->isGood() ) {
00091                                 $wgOut->addHTML( '<h2>' . $this->prepareMessage( 'filedeleteerror-short' ) . "</h2>\n" );
00092                                 $wgOut->addHTML( '<span class="error">' );
00093                                 $wgOut->addWikiText( $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) );
00094                                 $wgOut->addHTML( '</span>' );
00095                         }
00096                         if( $status->ok ) {
00097                                 $wgOut->setPageTitle( wfMessage( 'actioncomplete' ) );
00098                                 $wgOut->addHTML( $this->prepareMessage( 'filedelete-success' ) );
00099                                 // Return to the main page if we just deleted all versions of the
00100                                 // file, otherwise go back to the description page
00101                                 $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() );
00102 
00103                                 if ( $wgRequest->getCheck( 'wpWatch' ) && $wgUser->isLoggedIn() ) {
00104                                         WatchAction::doWatch( $this->title, $wgUser );
00105                                 } elseif ( $this->title->userIsWatching() ) {
00106                                         WatchAction::doUnwatch( $this->title, $wgUser );
00107                                 }
00108                         }
00109                         return;
00110                 }
00111 
00112                 $this->showForm();
00113                 $this->showLogEntries();
00114         }
00115 
00126         public static function doDelete( &$title, &$file, &$oldimage, $reason, $suppress, User $user = null ) {
00127                 if ( $user === null ) {
00128                         global $wgUser;
00129                         $user = $wgUser;
00130                 }
00131 
00132                 if( $oldimage ) {
00133                         $page = null;
00134                         $status = $file->deleteOld( $oldimage, $reason, $suppress );
00135                         if( $status->ok ) {
00136                                 // Need to do a log item
00137                                 $log = new LogPage( 'delete' );
00138                                 $logComment = wfMsgForContent( 'deletedrevision', $oldimage );
00139                                 if( trim( $reason ) != '' ) {
00140                                         $logComment .= wfMsgForContent( 'colon-separator' ) . $reason;
00141                                 }
00142                                 $log->addEntry( 'delete', $title, $logComment );
00143                         }
00144                 } else {
00145                         $status = Status::newFatal( 'cannotdelete',
00146                                 wfEscapeWikiText( $title->getPrefixedText() )
00147                         );
00148                         $page = WikiPage::factory( $title );
00149                         $dbw = wfGetDB( DB_MASTER );
00150                         try {
00151                                 // delete the associated article first
00152                                 $error = '';
00153                                 if ( $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user ) >= WikiPage::DELETE_SUCCESS ) {
00154                                         $status = $file->delete( $reason, $suppress );
00155                                         if( $status->isOK() ) {
00156                                                 $dbw->commit();
00157                                         } else {
00158                                                 $dbw->rollback();
00159                                         }
00160                                 }
00161                         } catch ( MWException $e ) {
00162                                 // rollback before returning to prevent UI from displaying incorrect "View or restore N deleted edits?"
00163                                 $dbw->rollback();
00164                                 throw $e;
00165                         }
00166                 }
00167 
00168                 if ( $status->isOK() ) {
00169                         wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
00170                 }
00171 
00172                 return $status;
00173         }
00174 
00178         private function showForm() {
00179                 global $wgOut, $wgUser, $wgRequest;
00180 
00181                 if( $wgUser->isAllowed( 'suppressrevision' ) ) {
00182                         $suppress = "<tr id=\"wpDeleteSuppressRow\">
00183                                         <td></td>
00184                                         <td class='mw-input'><strong>" .
00185                                                 Xml::checkLabel( wfMsg( 'revdelete-suppress' ),
00186                                                         'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '3' ) ) .
00187                                         "</strong></td>
00188                                 </tr>";
00189                 } else {
00190                         $suppress = '';
00191                 }
00192 
00193                 $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $this->title->userIsWatching();
00194                 $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction(),
00195                         'id' => 'mw-img-deleteconfirm' ) ) .
00196                         Xml::openElement( 'fieldset' ) .
00197                         Xml::element( 'legend', null, wfMsg( 'filedelete-legend' ) ) .
00198                         Html::hidden( 'wpEditToken', $wgUser->getEditToken( $this->oldimage ) ) .
00199                         $this->prepareMessage( 'filedelete-intro' ) .
00200                         Xml::openElement( 'table', array( 'id' => 'mw-img-deleteconfirm-table' ) ) .
00201                         "<tr>
00202                                 <td class='mw-label'>" .
00203                                         Xml::label( wfMsg( 'filedelete-comment' ), 'wpDeleteReasonList' ) .
00204                                 "</td>
00205                                 <td class='mw-input'>" .
00206                                         Xml::listDropDown( 'wpDeleteReasonList',
00207                                                 wfMsgForContent( 'filedelete-reason-dropdown' ),
00208                                                 wfMsgForContent( 'filedelete-reason-otherlist' ), '', 'wpReasonDropDown', 1 ) .
00209                                 "</td>
00210                         </tr>
00211                         <tr>
00212                                 <td class='mw-label'>" .
00213                                         Xml::label( wfMsg( 'filedelete-otherreason' ), 'wpReason' ) .
00214                                 "</td>
00215                                 <td class='mw-input'>" .
00216                                         Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ),
00217                                                 array( 'type' => 'text', 'maxlength' => '255', 'tabindex' => '2', 'id' => 'wpReason' ) ) .
00218                                 "</td>
00219                         </tr>
00220                         {$suppress}";
00221                 if( $wgUser->isLoggedIn() ) {
00222                         $form .= "
00223                         <tr>
00224                                 <td></td>
00225                                 <td class='mw-input'>" .
00226                                         Xml::checkLabel( wfMsg( 'watchthis' ),
00227                                                 'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) .
00228                                 "</td>
00229                         </tr>";
00230                 }
00231                 $form .= "
00232                         <tr>
00233                                 <td></td>
00234                                 <td class='mw-submit'>" .
00235                                         Xml::submitButton( wfMsg( 'filedelete-submit' ),
00236                                                 array( 'name' => 'mw-filedelete-submit', 'id' => 'mw-filedelete-submit', 'tabindex' => '4' ) ) .
00237                                 "</td>
00238                         </tr>" .
00239                         Xml::closeElement( 'table' ) .
00240                         Xml::closeElement( 'fieldset' ) .
00241                         Xml::closeElement( 'form' );
00242 
00243                         if ( $wgUser->isAllowed( 'editinterface' ) ) {
00244                                 $title = Title::makeTitle( NS_MEDIAWIKI, 'Filedelete-reason-dropdown' );
00245                                 $link = Linker::link(
00246                                         $title,
00247                                         wfMsgHtml( 'filedelete-edit-reasonlist' ),
00248                                         array(),
00249                                         array( 'action' => 'edit' )
00250                                 );
00251                                 $form .= '<p class="mw-filedelete-editreasons">' . $link . '</p>';
00252                         }
00253 
00254                 $wgOut->addHTML( $form );
00255         }
00256 
00260         private function showLogEntries() {
00261                 global $wgOut;
00262                 $wgOut->addHTML( '<h2>' . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
00263                 LogEventsList::showLogExtract( $wgOut, 'delete', $this->title );
00264         }
00265 
00274         private function prepareMessage( $message ) {
00275                 global $wgLang;
00276                 if( $this->oldimage ) {
00277                         return wfMsgExt(
00278                                 "{$message}-old", # To ensure grep will find them: 'filedelete-intro-old', 'filedelete-nofile-old', 'filedelete-success-old'
00279                                 'parse',
00280                                 wfEscapeWikiText( $this->title->getText() ),
00281                                 $wgLang->date( $this->getTimestamp(), true ),
00282                                 $wgLang->time( $this->getTimestamp(), true ),
00283                                 wfExpandUrl( $this->file->getArchiveUrl( $this->oldimage ), PROTO_CURRENT ) );
00284                 } else {
00285                         return wfMsgExt(
00286                                 $message,
00287                                 'parse',
00288                                 wfEscapeWikiText( $this->title->getText() )
00289                         );
00290                 }
00291         }
00292 
00296         private function setHeaders() {
00297                 global $wgOut;
00298                 $wgOut->setPageTitle( wfMessage( 'filedelete', $this->title->getText() ) );
00299                 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00300                 $wgOut->addBacklinkSubtitle( $this->title );
00301         }
00302 
00308         public static function isValidOldSpec($oldimage) {
00309                 return strlen( $oldimage ) >= 16
00310                         && strpos( $oldimage, '/' ) === false
00311                         && strpos( $oldimage, '\\' ) === false;
00312         }
00313 
00324         public static function haveDeletableFile(&$file, &$oldfile, $oldimage) {
00325                 return $oldimage
00326                         ? $oldfile && $oldfile->exists() && $oldfile->isLocal()
00327                         : $file && $file->exists() && $file->isLocal();
00328         }
00329 
00335         private function getAction() {
00336                 $q = array();
00337                 $q['action'] = 'delete';
00338 
00339                 if( $this->oldimage )
00340                         $q['oldimage'] = $this->oldimage;
00341 
00342                 return $this->title->getLocalUrl( $q );
00343         }
00344 
00350         private function getTimestamp() {
00351                 return $this->oldfile->getTimestamp();
00352         }
00353 }