X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FImagePage.php;h=705cf2243b9434d733a61d18f9d7f94df49b743d;hb=4bb299cbce4cc0dffe3f9cda30e12c4cad3b2279;hp=8fff2988dc3cb5c6ad97af35d89038d080c5be1a;hpb=d25024f93fc0e42a1e03224204697f05c4bd1f29;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/ImagePage.php b/includes/ImagePage.php index 8fff2988dc..705cf2243b 100644 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@ -16,14 +16,21 @@ if( !defined( 'MEDIAWIKI' ) ) class ImagePage extends Article { /* private */ var $img; // Image object this page is shown for + /* private */ var $repo; var $mExtraDescription = false; + var $dupes; - function __construct( $title ) { + function __construct( $title, $time = false ) { parent::__construct( $title ); - $this->img = wfFindFile( $this->mTitle ); + $this->img = wfFindFile( $this->mTitle, $time ); if ( !$this->img ) { $this->img = wfLocalFile( $this->mTitle ); + $this->current = $this->img; + } else { + $this->current = $time ? wfLocalFile( $this->mTitle ) : $this->img; } + $this->repo = $this->img->getRepo(); + $this->dupes = null; } /** @@ -33,12 +40,28 @@ class ImagePage extends Article { function render() { global $wgOut; $wgOut->setArticleBodyOnly( true ); - $wgOut->addSecondaryWikitext( $this->getContent() ); + parent::view(); } function view() { global $wgOut, $wgShowEXIF, $wgRequest, $wgUser; + if ( $this->mTitle->getNamespace() == NS_IMAGE && $this->img->getRedirected() ) { + if ( $this->mTitle->getDBkey() == $this->img->getName() ) { + // mTitle is the same as the redirect target so ask Article + // to perform the redirect for us. + return Article::view(); + } else { + // mTitle is not the same as the redirect target so it is + // probably the redirect page itself. Fake the redirect symbol + $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); + $this->viewRedirect( Title::makeTitle( NS_IMAGE, $this->img->getName() ), + /* $overwriteSubtitle */ true, /* $forceKnown */ true ); + $this->viewUpdates(); + return; + } + } + $diff = $wgRequest->getVal( 'diff' ); $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); @@ -46,10 +69,10 @@ class ImagePage extends Article { return Article::view(); if ($wgShowEXIF && $this->img->exists()) { - $exif = $this->img->getExifData(); - $showmeta = count($exif) ? true : false; + // FIXME: bad interface, see note on MediaHandler::formatMetadata(). + $formattedMetadata = $this->img->formatMetadata(); + $showmeta = $formattedMetadata !== false; } else { - $exif = false; $showmeta = false; } @@ -64,35 +87,102 @@ class ImagePage extends Article { } else { # Just need to set the right headers $wgOut->setArticleFlag( true ); - $wgOut->setRobotpolicy( 'index,follow' ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); $this->viewUpdates(); } # Show shared description, if needed if ( $this->mExtraDescription ) { - $fol = wfMsg( 'shareddescriptionfollows' ); + $fol = wfMsgNoTrans( 'shareddescriptionfollows' ); if( $fol != '-' && !wfEmptyMsg( 'shareddescriptionfollows', $fol ) ) { $wgOut->addWikiText( $fol ); } $wgOut->addHTML( '
' . $this->mExtraDescription . '
' ); + } else { + $this->checkSharedConflict(); } $this->closeShowImage(); $this->imageHistory(); + // TODO: Cleanup the following + + $wgOut->addHTML( Xml::element( 'h2', + array( 'id' => 'filelinks' ), + wfMsg( 'imagelinks' ) ) . "\n" ); + $this->imageDupes(); + // TODO: We may want to find local images redirecting to a foreign + // file: "The following local files redirect to this file" + if ( $this->img->isLocal() ) $this->imageRedirects(); $this->imageLinks(); - if ( $exif ) { + if ( $showmeta ) { global $wgStylePath, $wgStyleVersion; $expand = htmlspecialchars( wfEscapeJsString( wfMsg( 'metadata-expand' ) ) ); $collapse = htmlspecialchars( wfEscapeJsString( wfMsg( 'metadata-collapse' ) ) ); $wgOut->addHTML( Xml::element( 'h2', array( 'id' => 'metadata' ), wfMsg( 'metadata' ) ). "\n" ); - $wgOut->addWikiText( $this->makeMetadataTable( $exif ) ); + $wgOut->addWikiText( $this->makeMetadataTable( $formattedMetadata ) ); + $wgOut->addScriptFile( 'metadata.js' ); $wgOut->addHTML( - "\n" . "\n" ); } } + + public function getRedirectTarget() { + if ( $this->img->isLocal() ) + return parent::getRedirectTarget(); + + // Foreign image page + $from = $this->img->getRedirected(); + $to = $this->img->getName(); + if ($from == $to) return null; + return $this->mRedirectTarget = Title::makeTitle( NS_IMAGE, $to ); + } + public function followRedirect() { + if ( $this->img->isLocal() ) + return parent::followRedirect(); + + $from = $this->img->getRedirected(); + $to = $this->img->getName(); + if ($from == $to) return false; + return Title::makeTitle( NS_IMAGE, $to ); + } + public function isRedirect( $text = false ) { + if ( $this->img->isLocal() ) + return parent::isRedirect( $text ); + + return (bool)$this->img->getRedirected(); + } + + public function isLocal() { + return $this->img->isLocal(); + } + + public function getFile() { + return $this->img; + } + + public function getDuplicates() { + if ( !is_null($this->dupes) ) return $this->dupes; + + if ( !( $hash = $this->img->getSha1() ) ) + return $this->dupes = array(); + $dupes = RepoGroup::singleton()->findBySha1( $hash ); + + // Remove duplicates with self and non matching file sizes + $self = $this->img->getRepoName().':'.$this->img->getName(); + $size = $this->img->getSize(); + foreach ( $dupes as $index => $file ) { + $key = $file->getRepoName().':'.$file->getName(); + if ( $key == $self ) + unset( $dupes[$index] ); + if ( $file->getSize() != $size ) + unset( $dupes[$index] ); + } + return $this->dupes = $dupes; + + } + /** * Create the TOC @@ -106,9 +196,9 @@ class ImagePage extends Article { global $wgLang; $r = ''; return $r; } @@ -116,52 +206,34 @@ class ImagePage extends Article { /** * Make a table with metadata to be shown in the output page. * + * FIXME: bad interface, see note on MediaHandler::formatMetadata(). + * * @access private * * @param array $exif The array containing the EXIF data * @return string */ - function makeMetadataTable( $exif ) { + function makeMetadataTable( $metadata ) { $r = wfMsg( 'metadata-help' ) . "\n\n"; $r .= "{| id=mw_metadata class=mw_metadata\n"; - $visibleFields = $this->visibleMetadataFields(); - foreach( $exif as $k => $v ) { - $tag = strtolower( $k ); - $msg = wfMsg( "exif-$tag" ); - $class = "exif-$tag"; - if( !in_array( $tag, $visibleFields ) ) { - $class .= ' collapsable'; + foreach ( $metadata as $type => $stuff ) { + foreach ( $stuff as $v ) { + $class = Sanitizer::escapeId( $v['id'] ); + if( $type == 'collapsed' ) { + $class .= ' collapsable'; + } + $r .= "|- class=\"$class\"\n"; + $r .= "!| {$v['name']}\n"; + $r .= "|| {$v['value']}\n"; } - $r .= "|- class=\"$class\"\n"; - $r .= "!| $msg\n"; - $r .= "|| $v\n"; } $r .= '|}'; return $r; } - /** - * Get a list of EXIF metadata items which should be displayed when - * the metadata table is collapsed. - * - * @return array of strings - * @access private - */ - function visibleMetadataFields() { - $fields = array(); - $lines = explode( "\n", wfMsgForContent( 'metadata-fields' ) ); - foreach( $lines as $line ) { - $matches = array(); - if( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) { - $fields[] = $matches[1]; - } - } - return $fields; - } - /** * Overloading Article's getContent method. - * + * * Omit noarticletext if sharedupload; text will be fetched from the * shared upload server if possible. */ @@ -173,7 +245,7 @@ class ImagePage extends Article { } function openShowImage() { - global $wgOut, $wgUser, $wgImageLimits, $wgRequest, $wgLang; + global $wgOut, $wgUser, $wgImageLimits, $wgRequest, $wgLang, $wgContLang; $full_url = $this->img->getURL(); $linkAttribs = false; @@ -192,6 +264,7 @@ class ImagePage extends Article { $maxWidth = $max[0]; $maxHeight = $max[1]; $sk = $wgUser->getSkin(); + $dirmark = $wgContLang->getDirMark(); if ( $this->img->exists() ) { # image @@ -209,14 +282,15 @@ class ImagePage extends Article { $mime = $this->img->getMimeType(); $showLink = false; $linkAttribs = array( 'href' => $full_url ); + $longDesc = $this->img->getLongDesc(); - wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this , &$wgOut ) ) ; + wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this , &$wgOut ) ) ; - if ( $this->img->allowInlineDisplay() and $width and $height) { + if ( $this->img->allowInlineDisplay() ) { # image # "Download high res version" link below the image - $msgsize = wfMsgHtml('file-info-size', $width_orig, $height_orig, $sk->formatSize( $this->img->getSize() ), $mime ); + #$msgsize = wfMsgHtml('file-info-size', $width_orig, $height_orig, $sk->formatSize( $this->img->getSize() ), $mime ); # We'll show a thumbnail of this image if ( $width > $maxWidth || $height > $maxHeight ) { # Calculate the thumbnail size. @@ -234,7 +308,7 @@ class ImagePage extends Article { } $msgbig = wfMsgHtml( 'show-big-image' ); $msgsmall = wfMsgExt( 'show-big-image-thumb', - array( 'parseinline' ), $width, $height ); + array( 'parseinline' ), $wgLang->formatNum( $width ), $wgLang->formatNum( $height ) ); } else { # Image is small enough to show full size on image page $msgbig = htmlspecialchars( $this->img->getName() ); @@ -248,23 +322,22 @@ class ImagePage extends Article { if( $this->img->mustRender() ) { $showLink = true; } else { - $anchorclose .= + $anchorclose .= $msgsmall . - '
' . Xml::tags( 'a', $linkAttribs, $msgbig ) . ' ' . $msgsize; + '
' . Xml::tags( 'a', $linkAttribs, $msgbig ) . "$dirmark " . $longDesc; } if ( $this->img->isMultipage() ) { $wgOut->addHTML( '
' ); } - $imgAttribs = array( - 'border' => 0, - 'alt' => $this->img->getTitle()->getPrefixedText() - ); - if ( $thumbnail ) { - $wgOut->addHTML( '
' . - "$select
$thumb1\n$thumb2
" ); + $select = Xml::tags( 'select', + array( 'id' => 'pageselector', 'name' => 'page' ), + implode( "\n", $options ) ); + + $wgOut->addHTML( + '
' . + Xml::openElement( 'form', $formParams ) . + Xml::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) . + wfMsgExt( 'imgmultigoto', array( 'parseinline', 'replaceafter' ), $select ) . + Xml::submitButton( wfMsg( 'imgmultigo' ) ) . + Xml::closeElement( 'form' ) . + "
$thumb1\n$thumb2
" + ); } } else { #if direct link is allowed but it's not a renderable image, show an icon. if ($this->img->isSafeFile()) { $icon= $this->img->iconThumb(); - $wgOut->addHTML( '' ); + $wgOut->addHTML( '' ); } $showLink = true; @@ -322,26 +403,14 @@ class ImagePage extends Article { if ($showLink) { - // Workaround for incorrect MIME type on SVGs uploaded in previous versions - if ($mime == 'image/svg') $mime = 'image/svg+xml'; - $filename = wfEscapeWikiText( $this->img->getName() ); - $info = wfMsg( 'file-info', $sk->formatSize( $this->img->getSize() ), $mime ); - $infores = ''; - // Check for MIME type. Other types may have more information in the future. - if (substr($mime,0,9) == 'image/svg' ) { - $infores = wfMsg('file-svg', $width_orig, $height_orig ) . '
'; - } - - global $wgContLang; - $dirmark = $wgContLang->getDirMark(); if (!$this->img->isSafeFile()) { - $warning = wfMsg( 'mediawarning' ); + $warning = wfMsgNoTrans( 'mediawarning' ); $wgOut->addWikiText( <<$infores +
[[Media:$filename|$filename]]$dirmark - $info + $longDesc
$warning
@@ -349,8 +418,8 @@ EOT ); } else { $wgOut->addWikiText( <<$infores -[[Media:$filename|$filename]]$dirmark $info +
+[[Media:$filename|$filename]]$dirmark $longDesc
EOT ); @@ -370,29 +439,78 @@ EOT } } + /** + * Show a notice that the file is from a shared repository + */ function printSharedImageText() { global $wgOut, $wgUser; $descUrl = $this->img->getDescriptionUrl(); $descText = $this->img->getDescriptionText(); - $s = "
" . wfMsgWikiHtml("sharedupload"); - if ( $descUrl && !$descText) { + $s = "
" . wfMsgWikiHtml( 'sharedupload' ); + if ( $descUrl ) { $sk = $wgUser->getSkin(); - $link = $sk->makeExternalLink( $descUrl, wfMsg('shareduploadwiki-linktext') ); - $s .= " " . wfMsgWikiHtml('shareduploadwiki', $link); + $link = $sk->makeExternalLink( $descUrl, wfMsg( 'shareduploadwiki-linktext' ) ); + $msg = ( $descText ) ? 'shareduploadwiki-desc' : 'shareduploadwiki'; + $msg = wfMsgExt( $msg, array( 'parseinline', 'replaceafter' ), $link ); + if ( $msg != '-' ) { + # Show message only if not voided by local sysops + $s .= $msg; + } } $s .= "
"; - $wgOut->addHTML($s); + $wgOut->addHTML( $s ); if ( $descText ) { $this->mExtraDescription = $descText; } } + /* + * Check for files with the same name on the foreign repos. + */ + function checkSharedConflict() { + global $wgOut, $wgUser; + $repoGroup = RepoGroup::singleton(); + if( !$repoGroup->hasForeignRepos() ) { + return; + } + if( !$this->img->isLocal() ) { + return; + } + + $this->dupFile = null; + $repoGroup->forEachForeignRepo( array( $this, 'checkSharedConflictCallback' ) ); + + if( !$this->dupFile ) + return; + $dupfile = $this->dupFile; + $same = ( + ($this->img->getSha1() == $dupfile->getSha1()) && + ($this->img->getSize() == $dupfile->getSize()) + ); + + $sk = $wgUser->getSkin(); + $descUrl = $dupfile->getDescriptionUrl(); + if( $same ) { + $link = $sk->makeExternalLink( $descUrl, wfMsg( 'shareduploadduplicate-linktext' ) ); + $wgOut->addHTML( '
' . wfMsgWikiHtml( 'shareduploadduplicate', $link ) . '
' ); + } else { + $link = $sk->makeExternalLink( $descUrl, wfMsg( 'shareduploadconflict-linktext' ) ); + $wgOut->addHTML( '
' . wfMsgWikiHtml( 'shareduploadconflict', $link ) . '
' ); + } + } + + function checkSharedConflictCallback( $repo ) { + $dupfile = $repo->newFile( $this->img->getTitle() ); + if( $dupfile->exists() ) + $this->dupFile = $dupfile; + return $dupfile->exists(); + } + function getUploadUrl() { - global $wgServer; $uploadTitle = SpecialPage::getTitleFor( 'Upload' ); - return $wgServer . $uploadTitle->getLocalUrl( 'wpDestFile=' . urlencode( $this->img->getName() ) ); + return $uploadTitle->getFullUrl( 'wpDestFile=' . urlencode( $this->img->getName() ) ); } /** @@ -406,19 +524,23 @@ EOT return; $sk = $wgUser->getSkin(); - + $wgOut->addHtml( '
    ' ); - + # "Upload a new version of this file" link if( UploadForm::userCanReUpload($wgUser,$this->img->name) ) { $ulink = $sk->makeExternalLink( $this->getUploadUrl(), wfMsg( 'uploadnewversion-linktext' ) ); $wgOut->addHtml( "
  • " ); } - + + # Link to Special:FileDuplicateSearch + $dupeLink = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'FileDuplicateSearch', $this->mTitle->getDBkey() ), wfMsgHtml( 'imagepage-searchdupe' ) ); + $wgOut->addHtml( "
  • {$dupeLink}
  • " ); + # External editing link $elink = $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'edit-externally' ), 'action=edit&externaledit=true&mode=file' ); $wgOut->addHtml( '
  • ' . $elink . '
    ' . wfMsgWikiHtml( 'edit-externally-help' ) . '
  • ' ); - + $wgOut->addHtml( '
' ); } @@ -438,28 +560,24 @@ EOT $sk = $wgUser->getSkin(); - $line = $this->img->nextHistoryLine(); - - if ( $line ) { - $list = new ImageHistoryList( $sk, $this->img ); - $s = $list->beginImageHistoryList() . - $list->imageHistoryLine( true, wfTimestamp(TS_MW, $line->img_timestamp), - $this->mTitle->getDBkey(), $line->img_user, - $line->img_user_text, $line->img_size, $line->img_description, - $line->img_width, $line->img_height - ); - - while ( $line = $this->img->nextHistoryLine() ) { - $s .= $list->imageHistoryLine( false, $line->img_timestamp, - $line->oi_archive_name, $line->img_user, - $line->img_user_text, $line->img_size, $line->img_description, - $line->img_width, $line->img_height - ); + if ( $this->img->exists() ) { + $list = new ImageHistoryList( $sk, $this->current ); + $file = $this->current; + $dims = $file->getDimensionsString(); + $s = $list->beginImageHistoryList(); + $s .= $list->imageHistoryLine( true, $file ); + // old image versions + $hist = $this->img->getHistory(); + foreach( $hist as $file ) { + $dims = $file->getDimensionsString(); + $s .= $list->imageHistoryLine( false, $file ); } $s .= $list->endImageHistoryList(); } else { $s=''; } $wgOut->addHTML( $s ); + $this->img->resetHistory(); // free db resources + # Exist check because we don't want to show this on pages where an image # doesn't exist along with the noimage message, that would suck. -ævar if( $wgUseExternalEditor && $this->img->exists() ) { @@ -471,208 +589,107 @@ EOT function imageLinks() { global $wgUser, $wgOut; - - $wgOut->addHTML( Xml::element( 'h2', array( 'id' => 'filelinks' ), wfMsg( 'imagelinks' ) ) . "\n" ); + + $limit = 100; $dbr = wfGetDB( DB_SLAVE ); - $page = $dbr->tableName( 'page' ); - $imagelinks = $dbr->tableName( 'imagelinks' ); - $sql = "SELECT page_namespace,page_title FROM $imagelinks,$page WHERE il_to=" . - $dbr->addQuotes( $this->mTitle->getDBkey() ) . " AND il_from=page_id"; - $sql = $dbr->limitResult($sql, 500, 0); - $res = $dbr->query( $sql, "ImagePage::imageLinks" ); + $res = $dbr->select( + array( 'imagelinks', 'page' ), + array( 'page_namespace', 'page_title' ), + array( 'il_to' => $this->mTitle->getDBkey(), 'il_from = page_id' ), + __METHOD__, + array( 'LIMIT' => $limit + 1) + ); if ( 0 == $dbr->numRows( $res ) ) { - $wgOut->addHtml( '

' . wfMsg( "nolinkstoimage" ) . "

\n" ); + $wgOut->addWikiMsg( 'nolinkstoimage' ); return; } - $wgOut->addHTML( '

' . wfMsg( 'linkstoimage' ) . "

\n
    " ); + $wgOut->addWikiMsg( 'linkstoimage' ); + $wgOut->addHTML( "
      \n" ); $sk = $wgUser->getSkin(); - while ( $s = $dbr->fetchObject( $res ) ) { - $name = Title::MakeTitle( $s->page_namespace, $s->page_title ); - $link = $sk->makeKnownLinkObj( $name, "" ); - $wgOut->addHTML( "
    • {$link}
    • \n" ); + $count = 0; + while ( $s = $res->fetchObject() ) { + $count++; + if ( $count <= $limit ) { + // We have not yet reached the extra one that tells us there is more to fetch + $name = Title::makeTitle( $s->page_namespace, $s->page_title ); + $link = $sk->makeKnownLinkObj( $name, "" ); + $wgOut->addHTML( "
    • {$link}
    • \n" ); + } } $wgOut->addHTML( "
    \n" ); + $res->free(); + + // Add a links to [[Special:Whatlinkshere]] + if ( $count > $limit ) + $wgOut->addWikiMsg( 'morelinkstoimage', $this->mTitle->getPrefixedDBkey() ); } - - function delete() + + function imageRedirects() { - global $wgUser, $wgOut, $wgRequest; + global $wgUser, $wgOut; + + $redirects = $this->getTitle()->getRedirectsHere( NS_IMAGE ); + if ( count( $redirects ) == 0 ) return; + - $confirm = $wgRequest->wasPosted(); - $reason = $wgRequest->getVal( 'wpReason' ); - $image = $wgRequest->getVal( 'image' ); - $oldimage = $wgRequest->getVal( 'oldimage' ); + $wgOut->addWikiMsg( 'redirectstofile' ); + $wgOut->addHTML( "
      \n" ); - # Only sysops can delete images. Previously ordinary users could delete - # old revisions, but this is no longer the case. - if ( !$wgUser->isAllowed('delete') ) { - $wgOut->permissionRequired( 'delete' ); - return; - } - if ( $wgUser->isBlocked() ) { - $wgOut->blockedPage(); - return; - } - if ( wfReadOnly() ) { - $wgOut->readOnlyPage(); - return; + $sk = $wgUser->getSkin(); + foreach ( $redirects as $title ) { + $link = $sk->makeKnownLinkObj( $title, "" ); + $wgOut->addHTML( "
    • {$link}
    • \n" ); } + $wgOut->addHTML( "
    \n" ); - # Better double-check that it hasn't been deleted yet! - $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) ); - if ( ( !is_null( $image ) ) - && ( '' == trim( $image ) ) ) { - $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); - return; - } + } + + function imageDupes() { + global $wgOut, $wgUser; + + $dupes = $this->getDuplicates(); + if ( count( $dupes ) == 0 ) return; - # Deleting old images doesn't require confirmation - if ( !is_null( $oldimage ) || $confirm ) { - if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) { - $this->doDelete( $reason ); - } else { - $wgOut->showFatalError( wfMsg( 'sessionfailure' ) ); - } - return; - } + $wgOut->addWikiMsg( 'duplicatesoffile' ); + $wgOut->addHTML( "
      \n" ); - if ( !is_null( $image ) ) { - $q = '&image=' . urlencode( $image ); - } else if ( !is_null( $oldimage ) ) { - $q = '&oldimage=' . urlencode( $oldimage ); - } else { - $q = ''; + $sk = $wgUser->getSkin(); + foreach ( $dupes as $file ) { + if ( $file->isLocal() ) + $link = $sk->makeKnownLinkObj( $file->getTitle(), "" ); + else + $link = $sk->makeExternalLink( $file->getDescriptionUrl(), + $file->getTitle()->getPrefixedText() ); + $wgOut->addHTML( "
    • {$link}
    • \n" ); } - return $this->confirmDelete( $q, $wgRequest->getText( 'wpReason' ) ); + $wgOut->addHTML( "
    \n" ); } - /* - * Delete an image. - * @param $reason User provided reason for deletion. + /** + * Delete the file, or an earlier version of it */ - function doDelete( $reason ) { - global $wgOut, $wgRequest; - - $oldimage = $wgRequest->getVal( 'oldimage' ); - - if ( !is_null( $oldimage ) ) { - if ( strlen( $oldimage ) < 16 ) { - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); - return; - } - if ( strstr( $oldimage, "/" ) || strstr( $oldimage, "\\" ) ) { - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); - return; - } - if ( !$this->doDeleteOldImage( $oldimage ) ) { - return; - } - $deleted = $oldimage; - } else { - $ok = $this->img->delete( $reason ); - if( !$ok ) { - # If the deletion operation actually failed, bug out: - $wgOut->showFileDeleteError( $this->img->getName() ); - return; - } - - # Image itself is now gone, and database is cleaned. - # Now we remove the image description page. - - $article = new Article( $this->mTitle ); - $article->doDeleteArticle( $reason ); # ignore errors - - $deleted = $this->img->getName(); + public function delete() { + if( !$this->img->exists() || !$this->img->isLocal() ) { + // Standard article deletion + Article::delete(); + return; } - - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); - $wgOut->setRobotpolicy( 'noindex,nofollow' ); - - $loglink = '[[Special:Log/delete|' . wfMsg( 'deletionlog' ) . ']]'; - $text = wfMsg( 'deletedtext', $deleted, $loglink ); - - $wgOut->addWikiText( $text ); - - $wgOut->returnToMain( false, $this->mTitle->getPrefixedText() ); + $deleter = new FileDeleteForm( $this->img ); + $deleter->execute(); } /** - * @return success + * Revert the file to an earlier version */ - function doDeleteOldImage( $oldimage ) - { - global $wgOut; - - $ok = $this->img->deleteOld( $oldimage, '' ); - if( !$ok ) { - # If we actually have a file and can't delete it, throw an error. - # Something went awry... - $wgOut->showFileDeleteError( "$oldimage" ); - } else { - # Log the deletion - $log = new LogPage( 'delete' ); - $log->addEntry( 'delete', $this->mTitle, wfMsg('deletedrevision',$oldimage) ); - } - return $ok; + public function revert() { + $reverter = new FileRevertForm( $this->img ); + $reverter->execute(); } - function revert() { - global $wgOut, $wgRequest, $wgUser; - - $oldimage = $wgRequest->getText( 'oldimage' ); - if ( strlen( $oldimage ) < 16 ) { - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); - return; - } - if ( strstr( $oldimage, "/" ) || strstr( $oldimage, "\\" ) ) { - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); - return; - } - - if ( wfReadOnly() ) { - $wgOut->readOnlyPage(); - return; - } - if( $wgUser->isAnon() ) { - $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' ); - return; - } - if ( ! $this->mTitle->userCan( 'edit' ) ) { - $wgOut->readOnlyPage( $this->getContent(), true ); - return; - } - if ( $wgUser->isBlocked() ) { - $wgOut->blockedPage(); - return; - } - if( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) { - $wgOut->showErrorPage( 'internalerror', 'sessionfailure' ); - return; - } - - $sourcePath = $this->img->getArchiveVirtualUrl( $oldimage ); - $result = $this->img->publish( $sourcePath ); - - if ( WikiError::isError( $result ) ) { - $this->showError( $result ); - return; - } - - # Record upload and update metadata cache - $this->img->recordUpload( $result, wfMsg( "reverted" ) ); - - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); - $wgOut->setRobotpolicy( 'noindex,nofollow' ); - $wgOut->addHTML( wfMsg( 'imagereverted' ) ); - - $descTitle = $this->img->getTitle(); - $wgOut->returnToMain( false, $descTitle->getPrefixedText() ); - } - /** * Override handling of action=purge */ @@ -690,99 +707,162 @@ EOT } /** - * Display an error from a wikitext-formatted WikiError object + * Display an error with a wikitext description */ - function showError( WikiError $error ) { + function showError( $description ) { global $wgOut; $wgOut->setPageTitle( wfMsg( "internalerror" ) ); $wgOut->setRobotpolicy( "noindex,nofollow" ); $wgOut->setArticleRelated( false ); $wgOut->enableClientCache( false ); - $wgOut->addWikiText( $error->getMessage() ); + $wgOut->addWikiText( $description ); } } /** - * @todo document + * Builds the image revision log shown on image pages + * * @addtogroup Media */ class ImageHistoryList { - var $img, $skin; - function ImageHistoryList( $skin, $img ) { + + protected $img, $skin, $title, $repo; + + public function __construct( $skin, $img ) { $this->skin = $skin; $this->img = $img; + $this->title = $img->getTitle(); } - function beginImageHistoryList() { - $s = "\n" . - Xml::element( 'h2', array( 'id' => 'filehistory' ), wfMsg( 'imghistory' ) ) . - "\n

    " . wfMsg( 'imghistlegend' ) . "

    \n".'
      '; - return $s; + public function beginImageHistoryList() { + global $wgOut, $wgUser; + return Xml::element( 'h2', array( 'id' => 'filehistory' ), wfMsg( 'filehist' ) ) + . $wgOut->parse( wfMsgNoTrans( 'filehist-help' ) ) + . Xml::openElement( 'table', array( 'class' => 'filehistory' ) ) . "\n"; } - function endImageHistoryList() { - $s = "
    \n"; - return $s; + public function endImageHistoryList() { + return "\n"; } - function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description, $width, $height ) { - global $wgUser, $wgLang, $wgTitle, $wgContLang; + public function imageHistoryLine( $iscur, $file ) { + global $wgUser, $wgLang, $wgContLang, $wgTitle; - $datetime = $wgLang->timeanddate( $timestamp, true ); - $del = wfMsgHtml( 'deleteimg' ); - $delall = wfMsgHtml( 'deleteimgcompletely' ); - $cur = wfMsgHtml( 'cur' ); - $local = $this->img->isLocal(); + $timestamp = wfTimestamp(TS_MW, $file->getTimestamp()); + $img = $iscur ? $file->getName() : $file->getArchiveName(); + $user = $file->getUser('id'); + $usertext = $file->getUser('text'); + $size = $file->getSize(); + $description = $file->getDescription(); + $dims = $file->getDimensionsString(); + $sha1 = $file->getSha1(); - if ( $iscur ) { - $url = htmlspecialchars( $this->img->getURL() ); - $rlink = $cur; - if ( $local && $wgUser->isAllowed('delete') ) { - $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() . - '&action=delete' ); - $style = $this->skin->getInternalLinkAttributes( $link, $delall ); + $local = $this->img->isLocal(); + $row = $css = ''; + + // Deletion link + if( $local && ($wgUser->isAllowed('delete') || $wgUser->isAllowed('deleterevision') ) ) { + # Link to remove from history + if( $wgUser->isAllowed( 'delete' ) ) { + $q = array(); + $q[] = 'action=delete'; + if( !$iscur ) + $q[] = 'oldimage=' . urlencode( $img ); + $row .= '' . $this->skin->makeKnownLinkObj( + $this->title, + wfMsgHtml( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' ), + implode( '&', $q ) + ); + $row .= ''; + } + # Link to hide content + if( $wgUser->isAllowed( 'deleterevision' ) ) { + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); + // If file is top revision or locked from this user, don't link + if( $iscur || !$file->userCan(File::DELETED_RESTRICTED) ) { + $del = wfMsgHtml( 'rev-delundel' ); + } else { + // If the file was hidden, link to sha-1 + list($ts,$name) = explode('!',$img,2); + $del = $this->skin->makeKnownLinkObj( $revdel, wfMsg( 'rev-delundel' ), + 'target=' . urlencode( $wgTitle->getPrefixedText() ) . + '&oldimage=' . urlencode( $ts ) ); + // Bolden oversighted content + if( $file->isDeleted(File::DELETED_RESTRICTED) ) + $del = "$del"; + } + $row .= "$del"; + } + } - $dlink = ''.$delall.''; + // Reversion link/current indicator + $row .= ''; + if( $iscur ) { + $row .= wfMsgHtml( 'filehist-current' ); + } elseif( $local && $wgUser->isLoggedIn() && $this->title->userCan( 'edit' ) ) { + if( $file->isDeleted(File::DELETED_FILE) ) { + $row .= wfMsgHtml('filehist-revert'); } else { - $dlink = $del; + $q = array(); + $q[] = 'action=revert'; + $q[] = 'oldimage=' . urlencode( $img ); + $q[] = 'wpEditToken=' . urlencode( $wgUser->editToken( $img ) ); + $row .= $this->skin->makeKnownLinkObj( $this->title, + wfMsgHtml( 'filehist-revert' ), + implode( '&', $q ) ); } + } + $row .= ''; + + // Date/time and image link + $row .= ""; + if( !$file->userCan(File::DELETED_FILE) ) { + # Don't link to unviewable files + $row .= '' . $wgLang->timeAndDate( $timestamp, true ) . ''; + } else if( $file->isDeleted(File::DELETED_FILE) ) { + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); + # Make a link to review the image + $url = $this->skin->makeKnownLinkObj( $revdel, $wgLang->timeAndDate( $timestamp, true ), + "target=".$wgTitle->getPrefixedText()."&file=$sha1.".$this->img->getExtension() ); + $row .= ''.$url.''; } else { - $url = htmlspecialchars( $this->img->getArchiveUrl( $img ) ); - if( $local && $wgUser->getID() != 0 && $wgTitle->userCan( 'edit' ) ) { - $token = urlencode( $wgUser->editToken( $img ) ); - $rlink = $this->skin->makeKnownLinkObj( $wgTitle, - wfMsgHtml( 'revertimg' ), 'action=revert&oldimage=' . - urlencode( $img ) . "&wpEditToken=$token" ); - $dlink = $this->skin->makeKnownLinkObj( $wgTitle, - $del, 'action=delete&oldimage=' . urlencode( $img ) . - "&wpEditToken=$token" ); - } else { - # Having live active links for non-logged in users - # means that bots and spiders crawling our site can - # inadvertently change content. Baaaad idea. - $rlink = wfMsgHtml( 'revertimg' ); - $dlink = $del; - } + $url = $iscur ? $this->img->getUrl() : $this->img->getArchiveUrl( $img ); + $row .= Xml::element( 'a', array( 'href' => $url ), $wgLang->timeAndDate( $timestamp, true ) ); } - if ( $local ) { - $userlink = $this->skin->userLink( $user, $usertext ) . $this->skin->userToolLinks( $user, $usertext ); + $row .= ""; + + // Image dimensions + $row .= ' ' . htmlspecialchars( $dims ); + + // File size + $row .= " (" . $this->skin->formatSize( $size ) . ')'; + + // Uploading user + $row .= ''; + if( $local ) { + // Hide deleted usernames + if( $file->isDeleted(File::DELETED_USER) ) + $row .= '' . wfMsgHtml( 'rev-deleted-user' ) . ''; + else + $row .= $this->skin->userLink( $user, $usertext ) . + $this->skin->userToolLinks( $user, $usertext ); } else { - $userlink = htmlspecialchars( $usertext ); + $row .= htmlspecialchars( $usertext ); } - $nbytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ), - $wgLang->formatNum( $size ) ); - $widthheight = wfMsgHtml( 'widthheight', $width, $height ); - $style = $this->skin->getInternalLinkAttributes( $url, $datetime ); - $s = "
  • ({$dlink}) ({$rlink}) {$datetime} . . {$userlink} . . {$widthheight} ({$nbytes})"; + // Don't show deleted descriptions + if ( $file->isDeleted(File::DELETED_COMMENT) ) { + $row .= ' ' . wfMsgHtml('rev-deleted-comment') . ''; + } else { + $row .= ' ' . $this->skin->commentBlock( $description, $this->title ); + } + $row .= ''; - $s .= $this->skin->commentBlock( $description, $wgTitle ); - $s .= "
  • \n"; - return $s; + wfRunHooks( 'ImagePageFileHistoryLine', array( &$file, &$row, &$css ) ); + $tagCSS = $css ? " class='$css'" : ""; + + return "{$row}\n"; } } - - -?>