r24884 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r24883‎ | r24884 | r24885 >
Date:20:53, 17 August 2007
Author:robchurch
Status:old
Tags:
Comment:
* Confirmation is now required when deleting old versions of files
* Users can now enter comments when deleting old versions of files
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/FileDeleteForm.php (added) (history)
  • /trunk/phase3/includes/ImagePage.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -898,6 +898,19 @@
899899 'filerevert-success',
900900 'filerevert-badversion',
901901 ),
 902+ 'filedelete' => array(
 903+ 'filedelete',
 904+ 'filedelete-legend',
 905+ 'filedelete-intro',
 906+ 'filedelete-intro-old',
 907+ 'filedelete-comment',
 908+ 'filedelete-submit',
 909+ 'filedelete-success',
 910+ 'filedelete-success-old',
 911+ 'filedelete-nofile',
 912+ 'filedelete-nofile-old',
 913+ 'filedelete-iscurrent',
 914+ ),
902915 'mimesearch' => array(
903916 'mimesearch',
904917 'mimesearch-summary',
@@ -2241,6 +2254,7 @@
22422255 'licenses' => '',
22432256 'imagelist' => 'Image list',
22442257 'filerevert' => 'File reversion',
 2258+ 'filedelete' => 'File deletion',
22452259 'mimesearch' => 'MIME search',
22462260 'unwatchedpages' => 'Unwatched pages',
22472261 'listredirects' => 'List redirects',
@@ -2383,4 +2397,4 @@
23842398 'enotif_subject',
23852399 'enotif_body',
23862400 'allmessagesnotsupportedDB',
2387 -);
 2401+);
\ No newline at end of file
Index: trunk/phase3/includes/ImagePage.php
@@ -480,141 +480,23 @@
481481 $wgOut->addHTML( "</ul>\n" );
482482 }
483483
484 - function delete()
485 - {
486 - global $wgUser, $wgOut, $wgRequest;
487 -
488 - if ( !$this->img->exists() || !$this->img->isLocal() ) {
489 - # Use standard article deletion
 484+ /**
 485+ * Delete the file, or an earlier version of it
 486+ */
 487+ public function delete() {
 488+ if( !$this->img->exists() || !$this->img->isLocal() ) {
 489+ // Standard article deletion
490490 Article::delete();
491491 return;
492492 }
493 -
494 - $confirm = $wgRequest->wasPosted();
495 - $reason = $wgRequest->getVal( 'wpReason' );
496 - $image = $wgRequest->getVal( 'image' );
497 - $oldimage = $wgRequest->getVal( 'oldimage' );
498 -
499 - # Only sysops can delete images. Previously ordinary users could delete
500 - # old revisions, but this is no longer the case.
501 - if ( !$wgUser->isAllowed('delete') ) {
502 - $wgOut->permissionRequired( 'delete' );
503 - return;
504 - }
505 - if ( $wgUser->isBlocked() ) {
506 - $wgOut->blockedPage();
507 - return;
508 - }
509 - if ( wfReadOnly() ) {
510 - $wgOut->readOnlyPage();
511 - return;
512 - }
513 -
514 - # Better double-check that it hasn't been deleted yet!
515 - $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) );
516 - if ( ( !is_null( $image ) )
517 - && ( '' == trim( $image ) ) ) {
518 - $wgOut->showFatalError( wfMsg( 'cannotdelete' ) );
519 - return;
520 - }
521 -
522 - # Deleting old images doesn't require confirmation
523 - if ( !is_null( $oldimage ) || $confirm ) {
524 - if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) {
525 - $this->doDeleteImage( $reason );
526 - } else {
527 - $wgOut->showFatalError( wfMsg( 'sessionfailure' ) );
528 - }
529 - return;
530 - }
531 -
532 - if ( !is_null( $image ) ) {
533 - $q = '&image=' . urlencode( $image );
534 - } else if ( !is_null( $oldimage ) ) {
535 - $q = '&oldimage=' . urlencode( $oldimage );
536 - } else {
537 - $q = '';
538 - }
539 - return $this->confirmDelete( $q, $wgRequest->getText( 'wpReason' ) );
 493+ $deleter = new FileDeleteForm( $this->img );
 494+ $deleter->execute();
540495 }
541496
542 - /*
543 - * Delete an image.
544 - * Called doDeleteImage() not doDelete() so that Article::delete() doesn't
545 - * call back to here.
546 - *
547 - * @param $reason User provided reason for deletion.
548 - */
549 - function doDeleteImage( $reason ) {
550 - global $wgOut, $wgRequest;
551 -
552 - $oldimage = $wgRequest->getVal( 'oldimage' );
553 -
554 - if ( !is_null( $oldimage ) ) {
555 - if ( strlen( $oldimage ) < 16 ) {
556 - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) );
557 - return;
558 - }
559 - if( strpos( $oldimage, '/' ) !== false || strpos( $oldimage, '\\' ) !== false ) {
560 - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) );
561 - return;
562 - }
563 - $status = $this->doDeleteOldImage( $oldimage );
564 - $deleted = $oldimage;
565 - } else {
566 - $status = $this->img->delete( $reason );
567 - if ( !$status->isGood() ) {
568 - // Warning or error
569 - $wgOut->addWikiText( $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) );
570 - }
571 - if ( $status->ok ) {
572 - # Image itself is now gone, and database is cleaned.
573 - # Now we remove the image description page.
574 - $article = new Article( $this->mTitle );
575 - $article->doDeleteArticle( $reason ); # ignore errors
576 - $deleted = $this->img->getName();
577 - }
578 - }
579 -
580 - $wgOut->setRobotpolicy( 'noindex,nofollow' );
581 -
582 - if ( !$status->ok ) {
583 - // Fatal error flagged
584 - $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
585 - $wgOut->returnToMain( false, $this->mTitle->getPrefixedText() );
586 - } else {
587 - // Operation completed
588 - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
589 - $loglink = '[[Special:Log/delete|' . wfMsg( 'deletionlog' ) . ']]';
590 - $text = wfMsg( 'deletedtext', $deleted, $loglink );
591 - $wgOut->addWikiText( $text );
592 - $wgOut->returnToMain( false, $this->mTitle->getPrefixedText() );
593 - }
594 - }
595 -
596497 /**
597 - * Delete an old revision of an image,
598 - * @return FileRepoStatus
599 - */
600 - function doDeleteOldImage( $oldimage ) {
601 - global $wgOut;
602 -
603 - $status = $this->img->deleteOld( $oldimage, '' );
604 - if( !$status->isGood() ) {
605 - $wgOut->addWikiText( $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) );
606 - }
607 - if ( $status->ok ) {
608 - # Log the deletion
609 - $log = new LogPage( 'delete' );
610 - $log->addEntry( 'delete', $this->mTitle, wfMsg('deletedrevision',$oldimage) );
611 - }
612 - return $status;
613 - }
614 -
615 - /**
616498 * Revert the file to an earlier version
617499 */
618 - function revert() {
 500+ public function revert() {
619501 $reverter = new FileRevertForm( $this->img );
620502 $reverter->execute();
621503 }
Index: trunk/phase3/includes/AutoLoader.php
@@ -101,6 +101,7 @@
102102 'ImagePage' => 'includes/ImagePage.php',
103103 'ImageHistoryList' => 'includes/ImagePage.php',
104104 'ImageRemote' => 'includes/ImageRemote.php',
 105+ 'FileDeleteForm' => 'includes/FileDeleteForm.php',
105106 'FileRevertForm' => 'includes/FileRevertForm.php',
106107 'Job' => 'includes/JobQueue.php',
107108 'EmaillingJob' => 'includes/EmaillingJob.php',
@@ -383,7 +384,4 @@
384385 require( $file );
385386 }
386387 }
387 -}
388 -
389 -
390 -
 388+}
\ No newline at end of file
Index: trunk/phase3/includes/FileDeleteForm.php
@@ -0,0 +1,202 @@
 2+<?php
 3+
 4+/**
 5+ * File deletion user interface
 6+ *
 7+ * @addtogroup Media
 8+ * @author Rob Church <robchur@gmail.com>
 9+ */
 10+class FileDeleteForm {
 11+
 12+ private $title = null;
 13+ private $file = null;
 14+ private $oldimage = '';
 15+
 16+ /**
 17+ * Constructor
 18+ *
 19+ * @param File $file File we're deleting
 20+ */
 21+ public function __construct( $file ) {
 22+ $this->title = $file->getTitle();
 23+ $this->file = $file;
 24+ }
 25+
 26+ /**
 27+ * Fulfil the request; shows the form or deletes the file,
 28+ * pending authentication, confirmation, etc.
 29+ */
 30+ public function execute() {
 31+ global $wgOut, $wgRequest, $wgUser, $wgLang, $wgServer;
 32+ $this->setHeaders();
 33+
 34+ if( wfReadOnly() ) {
 35+ $wgOut->readOnlyPage();
 36+ return;
 37+ } elseif( !$wgUser->isLoggedIn() ) {
 38+ $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
 39+ return;
 40+ } elseif( !$wgUser->isAllowed( 'delete' ) ) {
 41+ $wgOut->permissionError( 'delete' );
 42+ return;
 43+ } elseif( $wgUser->isBlocked() ) {
 44+ $wgOut->blockedPage();
 45+ return;
 46+ }
 47+
 48+ $this->oldimage = $wgRequest->getText( 'oldimage', false );
 49+ $token = $wgRequest->getText( 'wpEditToken' );
 50+ if( $this->oldimage && !$this->isValidOldSpec() ) {
 51+ $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars( $this->oldimage ) );
 52+ return;
 53+ }
 54+
 55+ if( !$this->haveDeletableFile() ) {
 56+ $wgOut->addHtml( $this->prepareMessage( 'filedelete-nofile' ) );
 57+ $wgOut->addReturnTo( $this->title );
 58+ return;
 59+ }
 60+
 61+ // Don't allow accidental deletion of a single file revision
 62+ // if this is, in fact, the current revision; things might break
 63+ if( $this->oldimage && $this->file->getTimestamp() == $this->getTimestamp() ) {
 64+ $wgOut->addHtml( wfMsgExt( 'filedelete-iscurrent', 'parse' ) );
 65+ $wgOut->addReturnTo( $this->title );
 66+ return;
 67+ }
 68+
 69+ // Perform the deletion if appropriate
 70+ if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) {
 71+ $comment = $wgRequest->getText( 'wpComment' );
 72+ if( $this->oldimage ) {
 73+ $status = $this->file->deleteOld( $this->oldimage, $comment );
 74+ if( $status->ok ) {
 75+ // Need to do a log item
 76+ $log = new LogPage( 'delete' );
 77+ $log->addEntry( 'delete', $this->title, wfMsg( 'deletedrevision' , $this->oldimage ) );
 78+ }
 79+ } else {
 80+ $status = $this->file->delete( $comment );
 81+ if( $status->ok ) {
 82+ // Need to delete the associated article
 83+ $article = new Article( $this->title );
 84+ $article->doDeleteArticle( $comment );
 85+ }
 86+ }
 87+ if( !$status->isGood() )
 88+ $wgOut->addWikiText( $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) );
 89+ if( $status->ok ) {
 90+ $wgOut->addHtml( $this->prepareMessage( 'filedelete-success' ) );
 91+ // Return to the main page if we just deleted all versions of the
 92+ // file, otherwise go back to the description page
 93+ $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() );
 94+ }
 95+ return;
 96+ }
 97+
 98+ // Show the form
 99+ $this->showForm();
 100+ }
 101+
 102+ /**
 103+ * Show the confirmation form
 104+ */
 105+ private function showForm() {
 106+ global $wgOut, $wgUser, $wgRequest, $wgLang, $wgContLang, $wgServer;
 107+
 108+ $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction() ) );
 109+ $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken( $this->oldimage ) );
 110+ $form .= '<fieldset><legend>' . wfMsgHtml( 'filedelete-legend' ) . '</legend>';
 111+ $form .= $this->prepareMessage( 'filedelete-intro' );
 112+
 113+ $form .= '<p>' . Xml::inputLabel( wfMsg( 'filedelete-comment' ), 'wpComment', 'wpComment', 60 ) . '</p>';
 114+ $form .= '<p>' . Xml::submitButton( wfMsg( 'filedelete-submit' ) ) . '</p>';
 115+ $form .= '</fieldset>';
 116+ $form .= '</form>';
 117+
 118+ $wgOut->addHtml( $form );
 119+ }
 120+
 121+ /**
 122+ * Prepare a message referring to the file being deleted,
 123+ * showing an appropriate message depending upon whether
 124+ * it's a current file or an old version
 125+ *
 126+ * @param string $message Message base
 127+ * @return string
 128+ */
 129+ private function prepareMessage( $message ) {
 130+ global $wgLang, $wgServer;
 131+ if( $this->oldimage ) {
 132+ return wfMsgExt(
 133+ "{$message}-old",
 134+ 'parse',
 135+ $this->title->getText(),
 136+ $wgLang->date( $this->getTimestamp() ),
 137+ $wgLang->time( $this->getTimestamp() ),
 138+ $wgServer . $this->file->getArchiveUrl( $this->oldimage )
 139+ );
 140+ } else {
 141+ return wfMsgExt(
 142+ $message,
 143+ 'parse',
 144+ $this->title->getText()
 145+ );
 146+ }
 147+ }
 148+
 149+ /**
 150+ * Set headers, titles and other bits
 151+ */
 152+ private function setHeaders() {
 153+ global $wgOut;
 154+ $wgOut->setPageTitle( wfMsg( 'filedelete', $this->title->getText() ) );
 155+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 156+ }
 157+
 158+ /**
 159+ * Is the provided `oldimage` value valid?
 160+ *
 161+ * @return bool
 162+ */
 163+ private function isValidOldSpec() {
 164+ return strlen( $this->oldimage ) >= 16
 165+ && strpos( $this->oldimage, '/' ) === false
 166+ && strpos( $this->oldimage, '\\' ) === false;
 167+ }
 168+
 169+ /**
 170+ * Could we delete the file specified? If an `oldimage`
 171+ * value was provided, does it correspond to an
 172+ * existing, local, old version of this file?
 173+ *
 174+ * @return bool
 175+ */
 176+ private function haveDeletableFile() {
 177+ $file = wfFindFile( $this->title, $this->oldimage );
 178+ return $file && $file->exists() && $file->isLocal();
 179+ }
 180+
 181+ /**
 182+ * Prepare the form action
 183+ *
 184+ * @return string
 185+ */
 186+ private function getAction() {
 187+ $q = array();
 188+ $q[] = 'action=delete';
 189+ if( $this->oldimage )
 190+ $q[] = 'oldimage=' . urlencode( $this->oldimage );
 191+ return $this->title->getLocalUrl( implode( '&', $q ) );
 192+ }
 193+
 194+ /**
 195+ * Extract the timestamp of the old version
 196+ *
 197+ * @return string
 198+ */
 199+ private function getTimestamp() {
 200+ return substr( $this->oldimage, 0, 14 );
 201+ }
 202+
 203+}
\ No newline at end of file
Property changes on: trunk/phase3/includes/FileDeleteForm.php
___________________________________________________________________
Added: svn:eol-style
1204 + native
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1502,6 +1502,19 @@
15031503 'filerevert-success' => "<span class=\"plainlinks\">'''[[Media:$1|$1]]''' has been reverted to the [$4 version as of $2, $3].</span>",
15041504 'filerevert-badversion' => 'There is no previous local version of this file with the provided timestamp.',
15051505
 1506+# File deletion
 1507+'filedelete' => 'Delete $1',
 1508+'filedelete-legend' => 'Delete file',
 1509+'filedelete-intro' => "You are deleting '''[[Media:$1|$1]]'''.",
 1510+'filedelete-intro-old' => "<span class=\"plainlinks\">You are deleting the version of '''[[Media:$1|$1]]''' as of [$4 $2, $3].</span>",
 1511+'filedelete-comment' => 'Comment:',
 1512+'filedelete-submit' => 'Delete',
 1513+'filedelete-success' => "'''$1''' has been deleted.",
 1514+'filedelete-success-old' => "<span class=\"plainlinks\">The version of '''[[Media:$1|$1]]''' as of $2, $3 has been deleted.</span>",
 1515+'filedelete-nofile' => "'''$1''' does not exist on this site.",
 1516+'filedelete-nofile-old' => "There is no version of '''$1''' dated $2, $3.",
 1517+'filedelete-iscurrent' => 'You are attempting to delete the most recent version of this file. Please revert to an older version first.',
 1518+
15061519 # MIME search
15071520 'mimesearch' => 'MIME search',
15081521 'mimesearch-summary' => 'This page enables the filtering of files for its MIME-type. Input: contenttype/subtype, e.g. <tt>image/jpeg</tt>.',
Index: trunk/phase3/RELEASE-NOTES
@@ -177,6 +177,8 @@
178178 * (bug 10937) Distinguish overwritten files in upload log
179179 * Introduce 'ArticleUpdateBeforeRedirect' hook; see docs/hooks.txt for more
180180 information
 181+* Confirmation is now required when deleting old versions of files
 182+* Users can now enter comments when deleting old versions of files
181183
182184 == Bugfixes since 1.10 ==
183185

Follow-up revisions

RevisionCommit summaryAuthorDate
r25016Merged revisions 24866-25015 via svnmerge from...david23:06, 21 August 2007

Status & tagging log