MediaWiki  REL1_21
FileDeleteForm.php
Go to the documentation of this file.
00001 <?php
00030 class FileDeleteForm {
00031 
00035         private $title = null;
00036 
00040         private $file = null;
00041 
00045         private $oldfile = null;
00046         private $oldimage = '';
00047 
00053         public function __construct( $file ) {
00054                 $this->title = $file->getTitle();
00055                 $this->file = $file;
00056         }
00057 
00062         public function execute() {
00063                 global $wgOut, $wgRequest, $wgUser, $wgUploadMaintenance;
00064 
00065                 $permissionErrors = $this->title->getUserPermissionsErrors( 'delete', $wgUser );
00066                 if ( count( $permissionErrors ) ) {
00067                         throw new PermissionsError( 'delete', $permissionErrors );
00068                 }
00069 
00070                 if ( wfReadOnly() ) {
00071                         throw new ReadOnlyError;
00072                 }
00073 
00074                 if ( $wgUploadMaintenance ) {
00075                         throw new ErrorPageError( 'filedelete-maintenance-title', 'filedelete-maintenance' );
00076                 }
00077 
00078                 $this->setHeaders();
00079 
00080                 $this->oldimage = $wgRequest->getText( 'oldimage', false );
00081                 $token = $wgRequest->getText( 'wpEditToken' );
00082                 # Flag to hide all contents of the archived revisions
00083                 $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed( 'suppressrevision' );
00084 
00085                 if( $this->oldimage ) {
00086                         $this->oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->title, $this->oldimage );
00087                 }
00088 
00089                 if( !self::haveDeletableFile( $this->file, $this->oldfile, $this->oldimage ) ) {
00090                         $wgOut->addHTML( $this->prepareMessage( 'filedelete-nofile' ) );
00091                         $wgOut->addReturnTo( $this->title );
00092                         return;
00093                 }
00094 
00095                 // Perform the deletion if appropriate
00096                 if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) {
00097                         $deleteReasonList = $wgRequest->getText( 'wpDeleteReasonList' );
00098                         $deleteReason = $wgRequest->getText( 'wpReason' );
00099 
00100                         if ( $deleteReasonList == 'other' ) {
00101                                 $reason = $deleteReason;
00102                         } elseif ( $deleteReason != '' ) {
00103                                 // Entry from drop down menu + additional comment
00104                                 $reason = $deleteReasonList . wfMessage( 'colon-separator' )
00105                                         ->inContentLanguage()->text() . $deleteReason;
00106                         } else {
00107                                 $reason = $deleteReasonList;
00108                         }
00109 
00110                         $status = self::doDelete( $this->title, $this->file, $this->oldimage, $reason, $suppress, $wgUser );
00111 
00112                         if( !$status->isGood() ) {
00113                                 $wgOut->addHTML( '<h2>' . $this->prepareMessage( 'filedeleteerror-short' ) . "</h2>\n" );
00114                                 $wgOut->addWikiText( '<div class="error">' . $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) . '</div>' );
00115                         }
00116                         if( $status->ok ) {
00117                                 $wgOut->setPageTitle( wfMessage( 'actioncomplete' ) );
00118                                 $wgOut->addHTML( $this->prepareMessage( 'filedelete-success' ) );
00119                                 // Return to the main page if we just deleted all versions of the
00120                                 // file, otherwise go back to the description page
00121                                 $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() );
00122 
00123                                 if ( $wgUser->isLoggedIn() && $wgRequest->getCheck( 'wpWatch' ) != $wgUser->isWatched( $this->title ) ) {
00124                                         if ( $wgRequest->getCheck( 'wpWatch' ) ) {
00125                                                 WatchAction::doWatch( $this->title, $wgUser );
00126                                         } else {
00127                                                 WatchAction::doUnwatch( $this->title, $wgUser );
00128                                         }
00129                                 }
00130                         }
00131                         return;
00132                 }
00133 
00134                 $this->showForm();
00135                 $this->showLogEntries();
00136         }
00137 
00150         public static function doDelete( &$title, &$file, &$oldimage, $reason, $suppress, User $user = null ) {
00151                 if ( $user === null ) {
00152                         global $wgUser;
00153                         $user = $wgUser;
00154                 }
00155 
00156                 if( $oldimage ) {
00157                         $page = null;
00158                         $status = $file->deleteOld( $oldimage, $reason, $suppress );
00159                         if( $status->ok ) {
00160                                 // Need to do a log item
00161                                 $logComment = wfMessage( 'deletedrevision', $oldimage )->inContentLanguage()->text();
00162                                 if( trim( $reason ) != '' ) {
00163                                         $logComment .= wfMessage( 'colon-separator' )
00164                                                 ->inContentLanguage()->text() . $reason;
00165                                 }
00166 
00167                                 $logtype = $suppress ? 'suppress' : 'delete';
00168 
00169                                 $logEntry = new ManualLogEntry( $logtype, 'delete' );
00170                                 $logEntry->setPerformer( $user );
00171                                 $logEntry->setTarget( $title );
00172                                 $logEntry->setComment( $logComment );
00173                                 $logid = $logEntry->insert();
00174                                 $logEntry->publish( $logid );
00175                         }
00176                 } else {
00177                         $status = Status::newFatal( 'cannotdelete',
00178                                 wfEscapeWikiText( $title->getPrefixedText() )
00179                         );
00180                         $page = WikiPage::factory( $title );
00181                         $dbw = wfGetDB( DB_MASTER );
00182                         try {
00183                                 // delete the associated article first
00184                                 $error = '';
00185                                 $deleteStatus = $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user );
00186                                 // doDeleteArticleReal() returns a non-fatal error status if the page
00187                                 // or revision is missing, so check for isOK() rather than isGood()
00188                                 if ( $deleteStatus->isOK() ) {
00189                                         $status = $file->delete( $reason, $suppress );
00190                                         if( $status->isOK() ) {
00191                                                 $dbw->commit( __METHOD__ );
00192                                         } else {
00193                                                 $dbw->rollback( __METHOD__ );
00194                                         }
00195                                 }
00196                         } catch ( MWException $e ) {
00197                                 // rollback before returning to prevent UI from displaying incorrect "View or restore N deleted edits?"
00198                                 $dbw->rollback( __METHOD__ );
00199                                 throw $e;
00200                         }
00201                 }
00202 
00203                 if ( $status->isOK() ) {
00204                         wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
00205                 }
00206 
00207                 return $status;
00208         }
00209 
00213         private function showForm() {
00214                 global $wgOut, $wgUser, $wgRequest;
00215 
00216                 if( $wgUser->isAllowed( 'suppressrevision' ) ) {
00217                         $suppress = "<tr id=\"wpDeleteSuppressRow\">
00218                                         <td></td>
00219                                         <td class='mw-input'><strong>" .
00220                                                 Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
00221                                                         'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '3' ) ) .
00222                                         "</strong></td>
00223                                 </tr>";
00224                 } else {
00225                         $suppress = '';
00226                 }
00227 
00228                 $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $wgUser->isWatched( $this->title );
00229                 $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction(),
00230                         'id' => 'mw-img-deleteconfirm' ) ) .
00231                         Xml::openElement( 'fieldset' ) .
00232                         Xml::element( 'legend', null, wfMessage( 'filedelete-legend' )->text() ) .
00233                         Html::hidden( 'wpEditToken', $wgUser->getEditToken( $this->oldimage ) ) .
00234                         $this->prepareMessage( 'filedelete-intro' ) .
00235                         Xml::openElement( 'table', array( 'id' => 'mw-img-deleteconfirm-table' ) ) .
00236                         "<tr>
00237                                 <td class='mw-label'>" .
00238                                         Xml::label( wfMessage( 'filedelete-comment' )->text(), 'wpDeleteReasonList' ) .
00239                                 "</td>
00240                                 <td class='mw-input'>" .
00241                                         Xml::listDropDown(
00242                                                 'wpDeleteReasonList',
00243                                                 wfMessage( 'filedelete-reason-dropdown' )->inContentLanguage()->text(),
00244                                                 wfMessage( 'filedelete-reason-otherlist' )->inContentLanguage()->text(),
00245                                                 '',
00246                                                 'wpReasonDropDown',
00247                                                 1
00248                                         ) .
00249                                 "</td>
00250                         </tr>
00251                         <tr>
00252                                 <td class='mw-label'>" .
00253                                         Xml::label( wfMessage( 'filedelete-otherreason' )->text(), 'wpReason' ) .
00254                                 "</td>
00255                                 <td class='mw-input'>" .
00256                                         Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ),
00257                                                 array( 'type' => 'text', 'maxlength' => '255', 'tabindex' => '2', 'id' => 'wpReason' ) ) .
00258                                 "</td>
00259                         </tr>
00260                         {$suppress}";
00261                 if( $wgUser->isLoggedIn() ) {
00262                         $form .= "
00263                         <tr>
00264                                 <td></td>
00265                                 <td class='mw-input'>" .
00266                                         Xml::checkLabel( wfMessage( 'watchthis' )->text(),
00267                                                 'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) .
00268                                 "</td>
00269                         </tr>";
00270                 }
00271                 $form .= "
00272                         <tr>
00273                                 <td></td>
00274                                 <td class='mw-submit'>" .
00275                                         Xml::submitButton( wfMessage( 'filedelete-submit' )->text(),
00276                                                 array( 'name' => 'mw-filedelete-submit', 'id' => 'mw-filedelete-submit', 'tabindex' => '4' ) ) .
00277                                 "</td>
00278                         </tr>" .
00279                         Xml::closeElement( 'table' ) .
00280                         Xml::closeElement( 'fieldset' ) .
00281                         Xml::closeElement( 'form' );
00282 
00283                         if ( $wgUser->isAllowed( 'editinterface' ) ) {
00284                                 $title = Title::makeTitle( NS_MEDIAWIKI, 'Filedelete-reason-dropdown' );
00285                                 $link = Linker::link(
00286                                         $title,
00287                                         wfMessage( 'filedelete-edit-reasonlist' )->escaped(),
00288                                         array(),
00289                                         array( 'action' => 'edit' )
00290                                 );
00291                                 $form .= '<p class="mw-filedelete-editreasons">' . $link . '</p>';
00292                         }
00293 
00294                 $wgOut->addHTML( $form );
00295         }
00296 
00300         private function showLogEntries() {
00301                 global $wgOut;
00302                 $deleteLogPage = new LogPage( 'delete' );
00303                 $wgOut->addHTML( '<h2>' . $deleteLogPage->getName()->escaped() . "</h2>\n" );
00304                 LogEventsList::showLogExtract( $wgOut, 'delete', $this->title );
00305         }
00306 
00315         private function prepareMessage( $message ) {
00316                 global $wgLang;
00317                 if( $this->oldimage ) {
00318                         return wfMessage(
00319                                 "{$message}-old", # To ensure grep will find them: 'filedelete-intro-old', 'filedelete-nofile-old', 'filedelete-success-old'
00320                                 wfEscapeWikiText( $this->title->getText() ),
00321                                 $wgLang->date( $this->getTimestamp(), true ),
00322                                 $wgLang->time( $this->getTimestamp(), true ),
00323                                 wfExpandUrl( $this->file->getArchiveUrl( $this->oldimage ), PROTO_CURRENT ) )->parseAsBlock();
00324                 } else {
00325                         return wfMessage(
00326                                 $message,
00327                                 wfEscapeWikiText( $this->title->getText() )
00328                         )->parseAsBlock();
00329                 }
00330         }
00331 
00335         private function setHeaders() {
00336                 global $wgOut;
00337                 $wgOut->setPageTitle( wfMessage( 'filedelete', $this->title->getText() ) );
00338                 $wgOut->setRobotPolicy( 'noindex,nofollow' );
00339                 $wgOut->addBacklinkSubtitle( $this->title );
00340         }
00341 
00347         public static function isValidOldSpec( $oldimage ) {
00348                 return strlen( $oldimage ) >= 16
00349                         && strpos( $oldimage, '/' ) === false
00350                         && strpos( $oldimage, '\\' ) === false;
00351         }
00352 
00363         public static function haveDeletableFile( &$file, &$oldfile, $oldimage ) {
00364                 return $oldimage
00365                         ? $oldfile && $oldfile->exists() && $oldfile->isLocal()
00366                         : $file && $file->exists() && $file->isLocal();
00367         }
00368 
00374         private function getAction() {
00375                 $q = array();
00376                 $q['action'] = 'delete';
00377 
00378                 if( $this->oldimage ) {
00379                         $q['oldimage'] = $this->oldimage;
00380                 }
00381 
00382                 return $this->title->getLocalUrl( $q );
00383         }
00384 
00390         private function getTimestamp() {
00391                 return $this->oldfile->getTimestamp();
00392         }
00393 }