From ec2af084d28e489e51c696fb7953a3a22eb1e4cf Mon Sep 17 00:00:00 2001 From: Brian Wolff Date: Sat, 5 Feb 2011 08:49:48 +0000 Subject: [PATCH] (bug 26548) Make multi-paged documents (PDFs) work with ForeignAPIRepo (aka InstantCommons). This adds a new parameter to the query=imageinfo (and query=stashimageinfo) that takes rendering parameters other than width and height. This could be page for pdf's and DjVu, or thumbtime for ogg's, etc. Syntax is &iiurlparam=param1=value1|param2=value2|... I'm not sure if that really fits with the normal way of doing things in the api, but couldn't think of anything better since the parameters are arbitrary. I also noticed that some of the pre-existing error codes in query=imageinfo seem to duplicate the module prefix. I'm not sure what the deal with that is, but i did not follow that example in the new error codes i introduced. Note: In order for this to work, both the foreign repo and the local wiki have to be running this code. --- RELEASE-NOTES | 3 + includes/api/ApiQueryImageInfo.php | 85 +++++++++++++++++++++++-- includes/api/ApiQueryStashImageInfo.php | 12 +++- includes/filerepo/ForeignAPIFile.php | 17 ++++- includes/filerepo/ForeignAPIRepo.php | 14 ++-- 5 files changed, 114 insertions(+), 17 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 884242063f..96a7da631a 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -115,6 +115,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * (bug 19751) Filesystem is now checked during image undeletion * Send last modified headers for Special:Recentchanges when RC patrol is enabled, but user cannot see rc patrol links. +* (bug 26548) ForeignAPIRepo (InstantCommons) now works with PDF files + and other multi-paged file formats. === API changes in 1.18 === * (bug 26339) Throw warning when truncating an overlarge API result @@ -140,6 +142,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * (bug 26650) Remove $wgAPICacheHelp in favour of $wgAPICacheHelpTimeout * (bug 24650) Fix API to work with categorylinks changes * Expose list of skins in meta=siteinfo +* (bug 26548) Add iiurlparam param to query=imageinfo and query=stashimageinfo === Languages updated in 1.18 === diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php index 02def1a272..355d172504 100644 --- a/includes/api/ApiQueryImageInfo.php +++ b/includes/api/ApiQueryImageInfo.php @@ -50,7 +50,7 @@ class ApiQueryImageInfo extends ApiQueryBase { $prop = array_flip( $params['prop'] ); - $scale = $this->getScale( $params ); + $thumbParams = $this->makeThumbParams( $params ); $pageIds = $this->getPageSet()->getAllTitlesByNamespace(); if ( !empty( $pageIds[NS_FILE] ) ) { @@ -117,8 +117,9 @@ class ApiQueryImageInfo extends ApiQueryBase { ) { $gotOne = true; + $this->validateThumbParams( $img, $thumbParams ); $fit = $this->addPageSubItem( $pageId, - self::getInfo( $img, $prop, $result, $scale ) ); + self::getInfo( $img, $prop, $result, $thumbParams ) ); if ( !$fit ) { if ( count( $pageIds[NS_IMAGE] ) == 1 ) { // See the 'the user is screwed' comment above @@ -184,9 +185,25 @@ class ApiQueryImageInfo extends ApiQueryBase { * @return Array or Null: key-val array of 'width' and 'height', or null */ public function getScale( $params ) { + wfDeprecated( __METHOD__ ); + if ( !isset( $params['urlparam'] ) ) { + // In case there are subclasses that + // don't have this param set to anything. + $params['urlparam'] = null; + } + return $this->makeThumbParams( $params ); + } + + /* Take parameters for transforming thumbnail, validate and turn into array. + * @param $params Array: Parameters from the request. + * @return Array or null: If array, suitable to passing to $file->transform. + */ + public function makeThumbParams( $params ) { $p = $this->getModulePrefix(); + + // Height and width. if ( $params['urlheight'] != -1 && $params['urlwidth'] == -1 ) { - $this->dieUsage( "${p}urlheight cannot be used without {$p}urlwidth", "{$p}urlwidth" ); + $this->dieUsage( "{$p}urlheight cannot be used without {$p}urlwidth", "{$p}urlwidth" ); } if ( $params['urlwidth'] != -1 ) { @@ -195,10 +212,56 @@ class ApiQueryImageInfo extends ApiQueryBase { $scale['height'] = $params['urlheight']; } else { $scale = null; + if ( $params['urlparam'] ) { + $this->dieUsage( "{$p}urlparam requires {$p}urlwidth", "urlparam_no_width" ); + } + return $scale; + } + + // Other parameters. + if ( is_array( $params['urlparam'] ) ) { + foreach( $params['urlparam'] as $item ) { + $parameter = explode( '=', $item, 2 ); + + if ( count( $parameter ) !== 2 + || $parameter[0] === 'width' + || $parameter[0] === 'height' + ) { + $this->dieUsage( "Invalid value for {$p}urlparam ($item)", "urlparam" ); + } + $scale[$parameter[0]] = $parameter[1]; + } } return $scale; } + /** Validate the thumb parameters, give error if invalid. + * + * We do this later than makeThumbParams, since we need the image + * to know which handler, since handlers can make their own parameters. + * @param File $image Image that params are for. + * @param Array $thumbParams thumbnail parameters + */ + protected function validateThumbParams ( $image, $thumbParams ) { + if ( !$thumbParams ) return; + $p = $this->getModulePrefix(); + + $h = $image->getHandler(); + if ( !h ) { + // No handler, so no value for iiurlparam is valid. + $this->dieUsage( "Invalid value for {$p}urlparam", "urlparam" ); + } + foreach ( $thumbParams as $name => $value ) { + if ( !$h->validateParam( $name, $value ) ) { + /* This doesn't work well with height=-1 placeholder */ + if ( $name === 'height' ) continue; + $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" ); + } + } + // This could also potentially check normaliseParams as well, However that seems + // to fall more into a thumbnail rendering error than a user input error, and + // will be checked by the transform functions. + } /** * Get result information for an image revision @@ -206,10 +269,10 @@ class ApiQueryImageInfo extends ApiQueryBase { * @param $file File object * @param $prop Array of properties to get (in the keys) * @param $result ApiResult object - * @param $scale Array containing 'width' and 'height' items, or null + * @param $thumbParams Array containing 'width' and 'height' items, or null * @return Array: result array */ - static function getInfo( $file, $prop, $result, $scale = null ) { + static function getInfo( $file, $prop, $result, $thumbParams = null ) { $vals = array(); if ( isset( $prop['timestamp'] ) ) { $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $file->getTimestamp() ); @@ -237,8 +300,8 @@ class ApiQueryImageInfo extends ApiQueryBase { } } if ( isset( $prop['url'] ) ) { - if ( !is_null( $scale ) && !$file->isOld() ) { - $mto = $file->transform( array( 'width' => $scale['width'], 'height' => $scale['height'] ) ); + if ( !is_null( $thumbParams ) && !$file->isOld() ) { + $mto = $file->transform( $thumbParams ); if ( $mto && !$mto->isError() ) { $vals['thumburl'] = wfExpandUrl( $mto->getUrl() ); @@ -352,6 +415,9 @@ class ApiQueryImageInfo extends ApiQueryBase { ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_DFLT => -1 ), + 'urlparam' => array( + ApiBase::PARAM_ISMULTI => true, + ), 'continue' => null, ); } @@ -406,6 +472,8 @@ class ApiQueryImageInfo extends ApiQueryBase { 'urlwidth' => array( "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.", 'Only the current version of the image can be scaled' ), 'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth", + 'urlparam' => array( "Other rending parameters, such as page=2 for multipaged documents.", + "Multiple parameters should be seperated with a |. {$p}urlwidth must also be used"), 'limit' => 'How many image revisions to return', 'start' => 'Timestamp to start listing from', 'end' => 'Timestamp to stop listing at', @@ -418,8 +486,11 @@ class ApiQueryImageInfo extends ApiQueryBase { } public function getPossibleErrors() { + $p = $this->getModulePrefix(); return array_merge( parent::getPossibleErrors(), array( array( 'code' => 'iiurlwidth', 'info' => 'iiurlheight cannot be used without iiurlwidth' ), + array( 'code' => 'urlparam', 'info' => "Invalid value for {$p}urlparam" ), + array( 'code' => 'urlparam_no_width', 'info' => "iiurlparam requires {$p}urlwidth" ), ) ); } diff --git a/includes/api/ApiQueryStashImageInfo.php b/includes/api/ApiQueryStashImageInfo.php index bcd8196acc..84f7560057 100644 --- a/includes/api/ApiQueryStashImageInfo.php +++ b/includes/api/ApiQueryStashImageInfo.php @@ -37,7 +37,7 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { $prop = array_flip( $params['prop'] ); - $scale = $this->getScale( $params ); + $scale = $this->makeThumbParams( $params ); $result = $this->getResult(); @@ -46,6 +46,7 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { foreach ( $params['sessionkey'] as $sessionkey ) { $file = $stash->getFile( $sessionkey ); + $this->validateThumbParams( $file, $scale ); $imageInfo = self::getInfo( $file, $prop, $result, $scale ); $result->addValue( array( 'query', $this->getModuleName() ), null, $imageInfo ); $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), $modulePrefix ); @@ -97,7 +98,10 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { 'urlheight' => array( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_DFLT => -1 - ) + ), + 'urlparam' => array( + ApiBase::PARAM_ISMULTI => true, + ), ); } @@ -122,7 +126,9 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { ), 'sessionkey' => 'Session key that identifies a previous upload that was stashed temporarily.', 'urlwidth' => "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.", - 'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth" + 'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth", + 'urlparam' => array( "Other rending parameters, such as page=2 for multipaged documents.", + "Multiple parameters should be seperated with a |. {$p}urlwidth must also be used" ), ); } diff --git a/includes/filerepo/ForeignAPIFile.php b/includes/filerepo/ForeignAPIFile.php index 56fed75e41..f78a2a3ed3 100644 --- a/includes/filerepo/ForeignAPIFile.php +++ b/includes/filerepo/ForeignAPIFile.php @@ -76,10 +76,25 @@ class ForeignAPIFile extends File { // show icon return parent::transform( $params, $flags ); } + + $otherParams = ""; + // Not using implode, since associative array. + foreach ( $params as $name => $value ) { + if ( $name === 'width' || $name === 'height' ) { + continue; + } + $otherParams .= "{$name}={$value}|"; + } + // Remove the last | + if ( $otherParams !== "" ) { + $otherParams = substr( $otherParams, 0, -1 ); + } + $thumbUrl = $this->repo->getThumbUrlFromCache( $this->getName(), isset( $params['width'] ) ? $params['width'] : -1, - isset( $params['height'] ) ? $params['height'] : -1 ); + isset( $params['height'] ) ? $params['height'] : -1, + $otherParams ); return $this->handler->getTransform( $this, 'bogus', $thumbUrl, $params ); } diff --git a/includes/filerepo/ForeignAPIRepo.php b/includes/filerepo/ForeignAPIRepo.php index f465273b69..3b46f1454d 100644 --- a/includes/filerepo/ForeignAPIRepo.php +++ b/includes/filerepo/ForeignAPIRepo.php @@ -197,12 +197,13 @@ class ForeignAPIRepo extends FileRepo { return $ret; } - function getThumbUrl( $name, $width = -1, $height = -1, &$result = null ) { + function getThumbUrl( $name, $width = -1, $height = -1, &$result = null, $otherParams = '' ) { $data = $this->fetchImageQuery( array( 'titles' => 'File:' . $name, 'iiprop' => 'url|timestamp', 'iiurlwidth' => $width, 'iiurlheight' => $height, + 'iiurlparam' => $otherParams, 'prop' => 'imageinfo' ) ); $info = $this->getImageInfo( $data ); @@ -224,15 +225,16 @@ class ForeignAPIRepo extends FileRepo { * @param $name String is a dbkey form of a title * @param $width * @param $height + * @param String $param Other rendering parameters (page number, etc). | separated. */ - function getThumbUrlFromCache( $name, $width, $height ) { + function getThumbUrlFromCache( $name, $width, $height, $params="" ) { global $wgMemc; if ( !$this->canCacheThumbs() ) { - return $this->getThumbUrl( $name, $width, $height ); + return $this->getThumbUrl( $name, $width, $height, null, $params ); } $key = $this->getLocalCacheKey( 'ForeignAPIRepo', 'ThumbUrl', $name ); - $sizekey = "$width:$height"; + $sizekey = "$width:$height:$params"; /* Get the array of urls that we already know */ $knownThumbUrls = $wgMemc->get($key); @@ -248,7 +250,7 @@ class ForeignAPIRepo extends FileRepo { } $metadata = null; - $foreignUrl = $this->getThumbUrl( $name, $width, $height, $metadata ); + $foreignUrl = $this->getThumbUrl( $name, $width, $height, $metadata, $params ); if( !$foreignUrl ) { wfDebug( __METHOD__ . " Could not find thumburl\n" ); @@ -273,7 +275,7 @@ class ForeignAPIRepo extends FileRepo { $diff = abs( $modified - $current ); if( $remoteModified < $modified && $diff < $this->fileCacheExpiry ) { /* Use our current and already downloaded thumbnail */ - $knownThumbUrls["$width:$height"] = $localUrl; + $knownThumbUrls[$sizekey] = $localUrl; $wgMemc->set( $key, $knownThumbUrls, $this->apiThumbCacheExpiry ); return $localUrl; } -- 2.20.1