* (bug 18011) Special:FileDuplicateSearch UI fixes and remote file repo support
authorBrion Vibber <brion@users.mediawiki.org>
Mon, 7 Feb 2011 02:35:35 +0000 (02:35 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Mon, 7 Feb 2011 02:35:35 +0000 (02:35 +0000)
Fixes:
- now accepts file titles with or without File: prefix instead of demanding you must remove it
- moved result summary line from bottom to top
- added a line telling you no file was found if it wasn't found
- now pulls the reference file's SHA-1 via FileRepo, so can give it a remote file (eg from Commons)
- now pulls duplicate files via the main RepoGroup instead of querying image table manually, so turns up remote duplicates
- dropped the QueryPage standard paging header/footer; file dupe lists are usually very short and it's not worth copying the infrastructure

To make this work, I switched the special page class from using the standard QueryPage paths to doing the query and list itself; QueryPage is currently very tightly tied in to database queries, and doesn't provide a very clean way to drop in an alternative way of looking stuff up (say an API query or just getting a big array you've gotten from somewhere). If that gets improved, this page should be cleaned up to use more of the QueryPage infrastructure again so it's pretty and doesn't scare people coming in to maintain it.

Localization changes:
- added fileduplicatesearch-noresults message
- changed fileduplicatesearch-summary in English master to remove the supplementary line about taking out the 'File:' prefix

includes/specials/SpecialFileDuplicateSearch.php
languages/messages/MessagesEn.php

index e95a0ca..6b282c6 100644 (file)
  * @ingroup SpecialPage
  */
 class FileDuplicateSearchPage extends QueryPage {
-       protected $hash, $filename;
+       protected $hash = '', $filename = '';
+
+       /**
+        * @var File $file selected reference file, if present
+        */
+       protected $file = null;
 
        function __construct( $name = 'FileDuplicateSearch' ) {
                parent::__construct( $name );
@@ -43,6 +48,35 @@ class FileDuplicateSearchPage extends QueryPage {
                return array( 'filename' => $this->filename );
        }
 
+       /**
+        * Fetch dupes from all connected file repositories.
+        *
+        * @return Array of File objects
+        */
+       function getDupes() {
+               return RepoGroup::singleton()->findBySha1( $this->hash );
+       }
+
+       /**
+        *
+        * @param Array of File objects $dupes
+        */
+       function showList( $dupes ) {
+               global $wgUser, $wgOut;
+               $skin = $wgUser->getSkin();
+
+               $html = array();
+               $html[] = $this->openList( 0 );
+
+               foreach ( $dupes as $key => $dupe ) {
+                       $line = $this->formatResult( $skin, $dupe );
+                       $html[] = "<li>" . $line . "</li>";
+               }
+               $html[] = $this->closeList();
+
+               $wgOut->addHtml( implode( "\n", $html ) );
+       }
+
        function getQueryInfo() {
                return array(
                        'tables' => array( 'image' ),
@@ -63,11 +97,11 @@ class FileDuplicateSearchPage extends QueryPage {
                $this->outputHeader();
                
                $this->filename =  isset( $par ) ?  $par : $wgRequest->getText( 'filename' );
+               $this->file = null;
                $this->hash = '';
-               $title = Title::makeTitleSafe( NS_FILE, $this->filename );
+               $title = Title::newFromText( $this->filename, NS_FILE );
                if( $title && $title->getText() != '' ) {
-                       $dbr = wfGetDB( DB_SLAVE );
-                       $this->hash = $dbr->selectField( 'image', 'img_sha1', array( 'img_name' => $title->getDBkey() ), __METHOD__ );
+                       $this->file = wfFindFile( $title );
                }
 
                # Create the input form
@@ -82,11 +116,20 @@ class FileDuplicateSearchPage extends QueryPage {
                        Xml::closeElement( 'form' )
                );
 
+               if( $this->file ) {
+                       $this->hash = $this->file->getSha1();
+               } else {
+                       $wgOut->wrapWikiMsg(
+                               "<p class='mw-fileduplicatesearch-noresults'>\n$1\n</p>",
+                               array( 'fileduplicatesearch-noresults', wfEscapeWikiText( $this->filename ) )
+                       );
+               }
+
                if( $this->hash != '' ) {
                        $align = $wgContLang->alignEnd();
 
                        # Show a thumbnail of the file
-                       $img = wfFindFile( $title );
+                       $img = $this->file;
                        if ( $img ) {
                                $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
                                if( $thumb ) {
@@ -102,36 +145,46 @@ class FileDuplicateSearchPage extends QueryPage {
                                }
                        }
 
-                       parent::execute( $par );
+                       $dupes = $this->getDupes();
+                       $numRows = count( $dupes );
 
                        # Show a short summary
-                       if( $this->numRows == 1 ) {
+                       if( $numRows == 1 ) {
                                $wgOut->wrapWikiMsg(
                                        "<p class='mw-fileduplicatesearch-result-1'>\n$1\n</p>",
-                                       array( 'fileduplicatesearch-result-1', $this->filename )
+                                       array( 'fileduplicatesearch-result-1', wfEscapeWikiText( $this->filename ) )
                                );
-                       } elseif ( $this->numRows > 1 ) {
+                       } elseif ( $numRows ) {
                                $wgOut->wrapWikiMsg(
                                        "<p class='mw-fileduplicatesearch-result-n'>\n$1\n</p>",
-                                       array( 'fileduplicatesearch-result-n', $this->filename,
-                                               $wgLang->formatNum( $this->numRows - 1 ) )
+                                       array( 'fileduplicatesearch-result-n', wfEscapeWikiText( $this->filename ),
+                                               $wgLang->formatNum( $numRows - 1 ) )
                                );
                        }
+
+                       $this->showList( $dupes );
                }
        }
 
+       /**
+        *
+        * @param Skin $skin
+        * @param File $result
+        * @return string
+        */
        function formatResult( $skin, $result ) {
                global $wgContLang, $wgLang;
 
-               $nt = Title::makeTitle( NS_FILE, $result->title );
+               $nt = $result->getTitle();
                $text = $wgContLang->convert( $nt->getText() );
                $plink = $skin->link(
                        Title::newFromText( $nt->getPrefixedText() ),
                        $text
                );
 
-               $user = $skin->link( Title::makeTitle( NS_USER, $result->img_user_text ), $result->img_user_text );
-               $time = $wgLang->timeanddate( $result->img_timestamp );
+               $userText = $result->getUser( 'text' );
+               $user = $skin->link( Title::makeTitle( NS_USER, $userText ), $userText );
+               $time = $wgLang->timeanddate( $result->getTimestamp() );
 
                return "$plink . . $user . . $time";
        }
index fd86675..adbe49d 100644 (file)
@@ -4318,15 +4318,14 @@ Enter the file name without the "{{ns:file}}:" prefix.',
 
 # Special:FileDuplicateSearch
 'fileduplicatesearch'          => 'Search for duplicate files',
-'fileduplicatesearch-summary'  => 'Search for duplicate files based on hash values.
-
-Enter the filename without the "{{ns:file}}:" prefix.',
+'fileduplicatesearch-summary'  => 'Search for duplicate files based on hash values.',
 'fileduplicatesearch-legend'   => 'Search for a duplicate',
 'fileduplicatesearch-filename' => 'Filename:',
 'fileduplicatesearch-submit'   => 'Search',
 'fileduplicatesearch-info'     => '$1 × $2 pixel<br />File size: $3<br />MIME type: $4',
 'fileduplicatesearch-result-1' => 'The file "$1" has no identical duplication.',
 'fileduplicatesearch-result-n' => 'The file "$1" has {{PLURAL:$2|1 identical duplication|$2 identical duplications}}.',
+'fileduplicatesearch-noresults' => 'No file named "$1" found.',
 
 # Special:SpecialPages
 'specialpages'                   => 'Special pages',