[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * File deletion user interface. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @author Rob Church <[email protected]> 22 * @ingroup Media 23 */ 24 25 /** 26 * File deletion user interface 27 * 28 * @ingroup Media 29 */ 30 class FileDeleteForm { 31 32 /** 33 * @var Title 34 */ 35 private $title = null; 36 37 /** 38 * @var File 39 */ 40 private $file = null; 41 42 /** 43 * @var File 44 */ 45 private $oldfile = null; 46 private $oldimage = ''; 47 48 /** 49 * Constructor 50 * 51 * @param File $file File object we're deleting 52 */ 53 public function __construct( $file ) { 54 $this->title = $file->getTitle(); 55 $this->file = $file; 56 } 57 58 /** 59 * Fulfil the request; shows the form or deletes the file, 60 * pending authentication, confirmation, etc. 61 */ 62 public function execute() { 63 global $wgOut, $wgRequest, $wgUser, $wgUploadMaintenance; 64 65 $permissionErrors = $this->title->getUserPermissionsErrors( 'delete', $wgUser ); 66 if ( count( $permissionErrors ) ) { 67 throw new PermissionsError( 'delete', $permissionErrors ); 68 } 69 70 if ( wfReadOnly() ) { 71 throw new ReadOnlyError; 72 } 73 74 if ( $wgUploadMaintenance ) { 75 throw new ErrorPageError( 'filedelete-maintenance-title', 'filedelete-maintenance' ); 76 } 77 78 $this->setHeaders(); 79 80 $this->oldimage = $wgRequest->getText( 'oldimage', false ); 81 $token = $wgRequest->getText( 'wpEditToken' ); 82 # Flag to hide all contents of the archived revisions 83 $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed( 'suppressrevision' ); 84 85 if ( $this->oldimage ) { 86 $this->oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( 87 $this->title, 88 $this->oldimage 89 ); 90 } 91 92 if ( !self::haveDeletableFile( $this->file, $this->oldfile, $this->oldimage ) ) { 93 $wgOut->addHTML( $this->prepareMessage( 'filedelete-nofile' ) ); 94 $wgOut->addReturnTo( $this->title ); 95 return; 96 } 97 98 // Perform the deletion if appropriate 99 if ( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) { 100 $deleteReasonList = $wgRequest->getText( 'wpDeleteReasonList' ); 101 $deleteReason = $wgRequest->getText( 'wpReason' ); 102 103 if ( $deleteReasonList == 'other' ) { 104 $reason = $deleteReason; 105 } elseif ( $deleteReason != '' ) { 106 // Entry from drop down menu + additional comment 107 $reason = $deleteReasonList . wfMessage( 'colon-separator' ) 108 ->inContentLanguage()->text() . $deleteReason; 109 } else { 110 $reason = $deleteReasonList; 111 } 112 113 $status = self::doDelete( 114 $this->title, 115 $this->file, 116 $this->oldimage, 117 $reason, 118 $suppress, 119 $wgUser 120 ); 121 122 if ( !$status->isGood() ) { 123 $wgOut->addHTML( '<h2>' . $this->prepareMessage( 'filedeleteerror-short' ) . "</h2>\n" ); 124 $wgOut->addWikiText( '<div class="error">' . 125 $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) 126 . '</div>' ); 127 } 128 if ( $status->ok ) { 129 $wgOut->setPageTitle( wfMessage( 'actioncomplete' ) ); 130 $wgOut->addHTML( $this->prepareMessage( 'filedelete-success' ) ); 131 // Return to the main page if we just deleted all versions of the 132 // file, otherwise go back to the description page 133 $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() ); 134 135 WatchAction::doWatchOrUnwatch( $wgRequest->getCheck( 'wpWatch' ), $this->title, $wgUser ); 136 } 137 return; 138 } 139 140 $this->showForm(); 141 $this->showLogEntries(); 142 } 143 144 /** 145 * Really delete the file 146 * 147 * @param Title $title 148 * @param File $file 149 * @param string $oldimage Archive name 150 * @param string $reason Reason of the deletion 151 * @param bool $suppress Whether to mark all deleted versions as restricted 152 * @param User $user User object performing the request 153 * @throws MWException 154 * @return bool|Status 155 */ 156 public static function doDelete( &$title, &$file, &$oldimage, $reason, 157 $suppress, User $user = null 158 ) { 159 if ( $user === null ) { 160 global $wgUser; 161 $user = $wgUser; 162 } 163 164 if ( $oldimage ) { 165 $page = null; 166 $status = $file->deleteOld( $oldimage, $reason, $suppress, $user ); 167 if ( $status->ok ) { 168 // Need to do a log item 169 $logComment = wfMessage( 'deletedrevision', $oldimage )->inContentLanguage()->text(); 170 if ( trim( $reason ) != '' ) { 171 $logComment .= wfMessage( 'colon-separator' ) 172 ->inContentLanguage()->text() . $reason; 173 } 174 175 $logtype = $suppress ? 'suppress' : 'delete'; 176 177 $logEntry = new ManualLogEntry( $logtype, 'delete' ); 178 $logEntry->setPerformer( $user ); 179 $logEntry->setTarget( $title ); 180 $logEntry->setComment( $logComment ); 181 $logid = $logEntry->insert(); 182 $logEntry->publish( $logid ); 183 } 184 } else { 185 $status = Status::newFatal( 'cannotdelete', 186 wfEscapeWikiText( $title->getPrefixedText() ) 187 ); 188 $page = WikiPage::factory( $title ); 189 $dbw = wfGetDB( DB_MASTER ); 190 try { 191 // delete the associated article first 192 $error = ''; 193 $deleteStatus = $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user ); 194 // doDeleteArticleReal() returns a non-fatal error status if the page 195 // or revision is missing, so check for isOK() rather than isGood() 196 if ( $deleteStatus->isOK() ) { 197 $status = $file->delete( $reason, $suppress, $user ); 198 if ( $status->isOK() ) { 199 $dbw->commit( __METHOD__ ); 200 } else { 201 $dbw->rollback( __METHOD__ ); 202 } 203 } 204 } catch ( MWException $e ) { 205 // Rollback before returning to prevent UI from displaying 206 // incorrect "View or restore N deleted edits?" 207 $dbw->rollback( __METHOD__ ); 208 throw $e; 209 } 210 } 211 212 if ( $status->isOK() ) { 213 wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) ); 214 } 215 216 return $status; 217 } 218 219 /** 220 * Show the confirmation form 221 */ 222 private function showForm() { 223 global $wgOut, $wgUser, $wgRequest; 224 225 if ( $wgUser->isAllowed( 'suppressrevision' ) ) { 226 $suppress = "<tr id=\"wpDeleteSuppressRow\"> 227 <td></td> 228 <td class='mw-input'><strong>" . 229 Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(), 230 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '3' ) ) . 231 "</strong></td> 232 </tr>"; 233 } else { 234 $suppress = ''; 235 } 236 237 $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $wgUser->isWatched( $this->title ); 238 $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction(), 239 'id' => 'mw-img-deleteconfirm' ) ) . 240 Xml::openElement( 'fieldset' ) . 241 Xml::element( 'legend', null, wfMessage( 'filedelete-legend' )->text() ) . 242 Html::hidden( 'wpEditToken', $wgUser->getEditToken( $this->oldimage ) ) . 243 $this->prepareMessage( 'filedelete-intro' ) . 244 Xml::openElement( 'table', array( 'id' => 'mw-img-deleteconfirm-table' ) ) . 245 "<tr> 246 <td class='mw-label'>" . 247 Xml::label( wfMessage( 'filedelete-comment' )->text(), 'wpDeleteReasonList' ) . 248 "</td> 249 <td class='mw-input'>" . 250 Xml::listDropDown( 251 'wpDeleteReasonList', 252 wfMessage( 'filedelete-reason-dropdown' )->inContentLanguage()->text(), 253 wfMessage( 'filedelete-reason-otherlist' )->inContentLanguage()->text(), 254 '', 255 'wpReasonDropDown', 256 1 257 ) . 258 "</td> 259 </tr> 260 <tr> 261 <td class='mw-label'>" . 262 Xml::label( wfMessage( 'filedelete-otherreason' )->text(), 'wpReason' ) . 263 "</td> 264 <td class='mw-input'>" . 265 Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ), 266 array( 'type' => 'text', 'maxlength' => '255', 'tabindex' => '2', 'id' => 'wpReason' ) ) . 267 "</td> 268 </tr> 269 {$suppress}"; 270 if ( $wgUser->isLoggedIn() ) { 271 $form .= " 272 <tr> 273 <td></td> 274 <td class='mw-input'>" . 275 Xml::checkLabel( wfMessage( 'watchthis' )->text(), 276 'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) . 277 "</td> 278 </tr>"; 279 } 280 $form .= " 281 <tr> 282 <td></td> 283 <td class='mw-submit'>" . 284 Xml::submitButton( 285 wfMessage( 'filedelete-submit' )->text(), 286 array( 287 'name' => 'mw-filedelete-submit', 288 'id' => 'mw-filedelete-submit', 289 'tabindex' => '4' 290 ) 291 ) . 292 "</td> 293 </tr>" . 294 Xml::closeElement( 'table' ) . 295 Xml::closeElement( 'fieldset' ) . 296 Xml::closeElement( 'form' ); 297 298 if ( $wgUser->isAllowed( 'editinterface' ) ) { 299 $title = Title::makeTitle( NS_MEDIAWIKI, 'Filedelete-reason-dropdown' ); 300 $link = Linker::link( 301 $title, 302 wfMessage( 'filedelete-edit-reasonlist' )->escaped(), 303 array(), 304 array( 'action' => 'edit' ) 305 ); 306 $form .= '<p class="mw-filedelete-editreasons">' . $link . '</p>'; 307 } 308 309 $wgOut->addHTML( $form ); 310 } 311 312 /** 313 * Show deletion log fragments pertaining to the current file 314 */ 315 private function showLogEntries() { 316 global $wgOut; 317 $deleteLogPage = new LogPage( 'delete' ); 318 $wgOut->addHTML( '<h2>' . $deleteLogPage->getName()->escaped() . "</h2>\n" ); 319 LogEventsList::showLogExtract( $wgOut, 'delete', $this->title ); 320 } 321 322 /** 323 * Prepare a message referring to the file being deleted, 324 * showing an appropriate message depending upon whether 325 * it's a current file or an old version 326 * 327 * @param string $message Message base 328 * @return string 329 */ 330 private function prepareMessage( $message ) { 331 global $wgLang; 332 if ( $this->oldimage ) { 333 # Message keys used: 334 # 'filedelete-intro-old', 'filedelete-nofile-old', 'filedelete-success-old' 335 return wfMessage( 336 "{$message}-old", 337 wfEscapeWikiText( $this->title->getText() ), 338 $wgLang->date( $this->getTimestamp(), true ), 339 $wgLang->time( $this->getTimestamp(), true ), 340 wfExpandUrl( $this->file->getArchiveUrl( $this->oldimage ), PROTO_CURRENT ) )->parseAsBlock(); 341 } else { 342 return wfMessage( 343 $message, 344 wfEscapeWikiText( $this->title->getText() ) 345 )->parseAsBlock(); 346 } 347 } 348 349 /** 350 * Set headers, titles and other bits 351 */ 352 private function setHeaders() { 353 global $wgOut; 354 $wgOut->setPageTitle( wfMessage( 'filedelete', $this->title->getText() ) ); 355 $wgOut->setRobotPolicy( 'noindex,nofollow' ); 356 $wgOut->addBacklinkSubtitle( $this->title ); 357 } 358 359 /** 360 * Is the provided `oldimage` value valid? 361 * 362 * @param string $oldimage 363 * @return bool 364 */ 365 public static function isValidOldSpec( $oldimage ) { 366 return strlen( $oldimage ) >= 16 367 && strpos( $oldimage, '/' ) === false 368 && strpos( $oldimage, '\\' ) === false; 369 } 370 371 /** 372 * Could we delete the file specified? If an `oldimage` 373 * value was provided, does it correspond to an 374 * existing, local, old version of this file? 375 * 376 * @param File $file 377 * @param File $oldfile 378 * @param File $oldimage 379 * @return bool 380 */ 381 public static function haveDeletableFile( &$file, &$oldfile, $oldimage ) { 382 return $oldimage 383 ? $oldfile && $oldfile->exists() && $oldfile->isLocal() 384 : $file && $file->exists() && $file->isLocal(); 385 } 386 387 /** 388 * Prepare the form action 389 * 390 * @return string 391 */ 392 private function getAction() { 393 $q = array(); 394 $q['action'] = 'delete'; 395 396 if ( $this->oldimage ) { 397 $q['oldimage'] = $this->oldimage; 398 } 399 400 return $this->title->getLocalURL( $q ); 401 } 402 403 /** 404 * Extract the timestamp of the old version 405 * 406 * @return string 407 */ 408 private function getTimestamp() { 409 return $this->oldfile->getTimestamp(); 410 } 411 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |