MediaWiki  REL1_24
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(
00087                 $this->title,
00088                 $this->oldimage
00089             );
00090         }
00091 
00092         if ( !self::haveDeletableFile( $this->file, $this->oldfile, $this->oldimage ) ) {
00093             $wgOut->addHTML( $this->prepareMessage( 'filedelete-nofile' ) );
00094             $wgOut->addReturnTo( $this->title );
00095             return;
00096         }
00097 
00098         // Perform the deletion if appropriate
00099         if ( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) {
00100             $deleteReasonList = $wgRequest->getText( 'wpDeleteReasonList' );
00101             $deleteReason = $wgRequest->getText( 'wpReason' );
00102 
00103             if ( $deleteReasonList == 'other' ) {
00104                 $reason = $deleteReason;
00105             } elseif ( $deleteReason != '' ) {
00106                 // Entry from drop down menu + additional comment
00107                 $reason = $deleteReasonList . wfMessage( 'colon-separator' )
00108                     ->inContentLanguage()->text() . $deleteReason;
00109             } else {
00110                 $reason = $deleteReasonList;
00111             }
00112 
00113             $status = self::doDelete(
00114                 $this->title,
00115                 $this->file,
00116                 $this->oldimage,
00117                 $reason,
00118                 $suppress,
00119                 $wgUser
00120             );
00121 
00122             if ( !$status->isGood() ) {
00123                 $wgOut->addHTML( '<h2>' . $this->prepareMessage( 'filedeleteerror-short' ) . "</h2>\n" );
00124                 $wgOut->addWikiText( '<div class="error">' .
00125                     $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' )
00126                     . '</div>' );
00127             }
00128             if ( $status->ok ) {
00129                 $wgOut->setPageTitle( wfMessage( 'actioncomplete' ) );
00130                 $wgOut->addHTML( $this->prepareMessage( 'filedelete-success' ) );
00131                 // Return to the main page if we just deleted all versions of the
00132                 // file, otherwise go back to the description page
00133                 $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() );
00134 
00135                 WatchAction::doWatchOrUnwatch( $wgRequest->getCheck( 'wpWatch' ), $this->title, $wgUser );
00136             }
00137             return;
00138         }
00139 
00140         $this->showForm();
00141         $this->showLogEntries();
00142     }
00143 
00156     public static function doDelete( &$title, &$file, &$oldimage, $reason,
00157         $suppress, User $user = null
00158     ) {
00159         if ( $user === null ) {
00160             global $wgUser;
00161             $user = $wgUser;
00162         }
00163 
00164         if ( $oldimage ) {
00165             $page = null;
00166             $status = $file->deleteOld( $oldimage, $reason, $suppress, $user );
00167             if ( $status->ok ) {
00168                 // Need to do a log item
00169                 $logComment = wfMessage( 'deletedrevision', $oldimage )->inContentLanguage()->text();
00170                 if ( trim( $reason ) != '' ) {
00171                     $logComment .= wfMessage( 'colon-separator' )
00172                         ->inContentLanguage()->text() . $reason;
00173                 }
00174 
00175                 $logtype = $suppress ? 'suppress' : 'delete';
00176 
00177                 $logEntry = new ManualLogEntry( $logtype, 'delete' );
00178                 $logEntry->setPerformer( $user );
00179                 $logEntry->setTarget( $title );
00180                 $logEntry->setComment( $logComment );
00181                 $logid = $logEntry->insert();
00182                 $logEntry->publish( $logid );
00183             }
00184         } else {
00185             $status = Status::newFatal( 'cannotdelete',
00186                 wfEscapeWikiText( $title->getPrefixedText() )
00187             );
00188             $page = WikiPage::factory( $title );
00189             $dbw = wfGetDB( DB_MASTER );
00190             try {
00191                 // delete the associated article first
00192                 $error = '';
00193                 $deleteStatus = $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user );
00194                 // doDeleteArticleReal() returns a non-fatal error status if the page
00195                 // or revision is missing, so check for isOK() rather than isGood()
00196                 if ( $deleteStatus->isOK() ) {
00197                     $status = $file->delete( $reason, $suppress, $user );
00198                     if ( $status->isOK() ) {
00199                         $dbw->commit( __METHOD__ );
00200                     } else {
00201                         $dbw->rollback( __METHOD__ );
00202                     }
00203                 }
00204             } catch ( MWException $e ) {
00205                 // Rollback before returning to prevent UI from displaying
00206                 // incorrect "View or restore N deleted edits?"
00207                 $dbw->rollback( __METHOD__ );
00208                 throw $e;
00209             }
00210         }
00211 
00212         if ( $status->isOK() ) {
00213             wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
00214         }
00215 
00216         return $status;
00217     }
00218 
00222     private function showForm() {
00223         global $wgOut, $wgUser, $wgRequest;
00224 
00225         if ( $wgUser->isAllowed( 'suppressrevision' ) ) {
00226             $suppress = "<tr id=\"wpDeleteSuppressRow\">
00227                     <td></td>
00228                     <td class='mw-input'><strong>" .
00229                         Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
00230                             'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '3' ) ) .
00231                     "</strong></td>
00232                 </tr>";
00233         } else {
00234             $suppress = '';
00235         }
00236 
00237         $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $wgUser->isWatched( $this->title );
00238         $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction(),
00239             'id' => 'mw-img-deleteconfirm' ) ) .
00240             Xml::openElement( 'fieldset' ) .
00241             Xml::element( 'legend', null, wfMessage( 'filedelete-legend' )->text() ) .
00242             Html::hidden( 'wpEditToken', $wgUser->getEditToken( $this->oldimage ) ) .
00243             $this->prepareMessage( 'filedelete-intro' ) .
00244             Xml::openElement( 'table', array( 'id' => 'mw-img-deleteconfirm-table' ) ) .
00245             "<tr>
00246                 <td class='mw-label'>" .
00247                     Xml::label( wfMessage( 'filedelete-comment' )->text(), 'wpDeleteReasonList' ) .
00248                 "</td>
00249                 <td class='mw-input'>" .
00250                     Xml::listDropDown(
00251                         'wpDeleteReasonList',
00252                         wfMessage( 'filedelete-reason-dropdown' )->inContentLanguage()->text(),
00253                         wfMessage( 'filedelete-reason-otherlist' )->inContentLanguage()->text(),
00254                         '',
00255                         'wpReasonDropDown',
00256                         1
00257                     ) .
00258                 "</td>
00259             </tr>
00260             <tr>
00261                 <td class='mw-label'>" .
00262                     Xml::label( wfMessage( 'filedelete-otherreason' )->text(), 'wpReason' ) .
00263                 "</td>
00264                 <td class='mw-input'>" .
00265                     Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ),
00266                         array( 'type' => 'text', 'maxlength' => '255', 'tabindex' => '2', 'id' => 'wpReason' ) ) .
00267                 "</td>
00268             </tr>
00269             {$suppress}";
00270         if ( $wgUser->isLoggedIn() ) {
00271             $form .= "
00272             <tr>
00273                 <td></td>
00274                 <td class='mw-input'>" .
00275                     Xml::checkLabel( wfMessage( 'watchthis' )->text(),
00276                         'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) .
00277                 "</td>
00278             </tr>";
00279         }
00280         $form .= "
00281             <tr>
00282                 <td></td>
00283                 <td class='mw-submit'>" .
00284                     Xml::submitButton(
00285                         wfMessage( 'filedelete-submit' )->text(),
00286                         array(
00287                             'name' => 'mw-filedelete-submit',
00288                             'id' => 'mw-filedelete-submit',
00289                             'tabindex' => '4'
00290                         )
00291                     ) .
00292                 "</td>
00293             </tr>" .
00294             Xml::closeElement( 'table' ) .
00295             Xml::closeElement( 'fieldset' ) .
00296             Xml::closeElement( 'form' );
00297 
00298             if ( $wgUser->isAllowed( 'editinterface' ) ) {
00299                 $title = Title::makeTitle( NS_MEDIAWIKI, 'Filedelete-reason-dropdown' );
00300                 $link = Linker::link(
00301                     $title,
00302                     wfMessage( 'filedelete-edit-reasonlist' )->escaped(),
00303                     array(),
00304                     array( 'action' => 'edit' )
00305                 );
00306                 $form .= '<p class="mw-filedelete-editreasons">' . $link . '</p>';
00307             }
00308 
00309         $wgOut->addHTML( $form );
00310     }
00311 
00315     private function showLogEntries() {
00316         global $wgOut;
00317         $deleteLogPage = new LogPage( 'delete' );
00318         $wgOut->addHTML( '<h2>' . $deleteLogPage->getName()->escaped() . "</h2>\n" );
00319         LogEventsList::showLogExtract( $wgOut, 'delete', $this->title );
00320     }
00321 
00330     private function prepareMessage( $message ) {
00331         global $wgLang;
00332         if ( $this->oldimage ) {
00333             # Message keys used:
00334             # 'filedelete-intro-old', 'filedelete-nofile-old', 'filedelete-success-old'
00335             return wfMessage(
00336                 "{$message}-old",
00337                 wfEscapeWikiText( $this->title->getText() ),
00338                 $wgLang->date( $this->getTimestamp(), true ),
00339                 $wgLang->time( $this->getTimestamp(), true ),
00340                 wfExpandUrl( $this->file->getArchiveUrl( $this->oldimage ), PROTO_CURRENT ) )->parseAsBlock();
00341         } else {
00342             return wfMessage(
00343                 $message,
00344                 wfEscapeWikiText( $this->title->getText() )
00345             )->parseAsBlock();
00346         }
00347     }
00348 
00352     private function setHeaders() {
00353         global $wgOut;
00354         $wgOut->setPageTitle( wfMessage( 'filedelete', $this->title->getText() ) );
00355         $wgOut->setRobotPolicy( 'noindex,nofollow' );
00356         $wgOut->addBacklinkSubtitle( $this->title );
00357     }
00358 
00365     public static function isValidOldSpec( $oldimage ) {
00366         return strlen( $oldimage ) >= 16
00367             && strpos( $oldimage, '/' ) === false
00368             && strpos( $oldimage, '\\' ) === false;
00369     }
00370 
00381     public static function haveDeletableFile( &$file, &$oldfile, $oldimage ) {
00382         return $oldimage
00383             ? $oldfile && $oldfile->exists() && $oldfile->isLocal()
00384             : $file && $file->exists() && $file->isLocal();
00385     }
00386 
00392     private function getAction() {
00393         $q = array();
00394         $q['action'] = 'delete';
00395 
00396         if ( $this->oldimage ) {
00397             $q['oldimage'] = $this->oldimage;
00398         }
00399 
00400         return $this->title->getLocalURL( $q );
00401     }
00402 
00408     private function getTimestamp() {
00409         return $this->oldfile->getTimestamp();
00410     }
00411 }