
catrope at svn
Jan 20, 2008, 10:41 AM
Post #1 of 1
(115 views)
Permalink
|
|
SVN: [29996] branches/ApiEdit_Vodafone/includes
|
|
Revision: 29996 Author: catrope Date: 2008-01-20 18:41:22 +0000 (Sun, 20 Jan 2008) Log Message: ----------- ApiEdit_Vodafone svnmerge part 3 Modified Paths: -------------- branches/ApiEdit_Vodafone/includes/AjaxFunctions.php branches/ApiEdit_Vodafone/includes/Article.php branches/ApiEdit_Vodafone/includes/CoreParserFunctions.php branches/ApiEdit_Vodafone/includes/DefaultSettings.php branches/ApiEdit_Vodafone/includes/Defines.php branches/ApiEdit_Vodafone/includes/EditPage.php branches/ApiEdit_Vodafone/includes/ExternalEdit.php branches/ApiEdit_Vodafone/includes/GlobalFunctions.php branches/ApiEdit_Vodafone/includes/HTMLCacheUpdate.php branches/ApiEdit_Vodafone/includes/ImagePage.php branches/ApiEdit_Vodafone/includes/Linker.php branches/ApiEdit_Vodafone/includes/MessageCache.php branches/ApiEdit_Vodafone/includes/Parser.php branches/ApiEdit_Vodafone/includes/Parser_OldPP.php branches/ApiEdit_Vodafone/includes/RawPage.php branches/ApiEdit_Vodafone/includes/SiteConfiguration.php branches/ApiEdit_Vodafone/includes/Skin.php branches/ApiEdit_Vodafone/includes/SpecialBlockip.php branches/ApiEdit_Vodafone/includes/SpecialExport.php branches/ApiEdit_Vodafone/includes/SpecialIpblocklist.php branches/ApiEdit_Vodafone/includes/SpecialUndelete.php branches/ApiEdit_Vodafone/includes/SpecialVersion.php branches/ApiEdit_Vodafone/includes/SpecialWithoutinterwiki.php branches/ApiEdit_Vodafone/includes/Title.php branches/ApiEdit_Vodafone/includes/Wiki.php branches/ApiEdit_Vodafone/includes/api/ApiBase.php branches/ApiEdit_Vodafone/includes/api/ApiBlock.php branches/ApiEdit_Vodafone/includes/api/ApiDelete.php branches/ApiEdit_Vodafone/includes/api/ApiLogin.php branches/ApiEdit_Vodafone/includes/api/ApiLogout.php branches/ApiEdit_Vodafone/includes/api/ApiMain.php branches/ApiEdit_Vodafone/includes/api/ApiMove.php branches/ApiEdit_Vodafone/includes/api/ApiProtect.php branches/ApiEdit_Vodafone/includes/api/ApiQueryAllmessages.php branches/ApiEdit_Vodafone/includes/api/ApiQueryAllpages.php branches/ApiEdit_Vodafone/includes/api/ApiQueryImageInfo.php branches/ApiEdit_Vodafone/includes/api/ApiRollback.php branches/ApiEdit_Vodafone/includes/api/ApiUnblock.php branches/ApiEdit_Vodafone/includes/api/ApiUndelete.php branches/ApiEdit_Vodafone/includes/filerepo/File.php branches/ApiEdit_Vodafone/includes/filerepo/FileRepo.php branches/ApiEdit_Vodafone/includes/filerepo/LocalFile.php branches/ApiEdit_Vodafone/includes/filerepo/LocalRepo.php branches/ApiEdit_Vodafone/includes/filerepo/RepoGroup.php Modified: branches/ApiEdit_Vodafone/includes/AjaxFunctions.php =================================================================== --- branches/ApiEdit_Vodafone/includes/AjaxFunctions.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/AjaxFunctions.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -86,7 +86,7 @@ $term = $wgContLang->ucfirst( $term ); $term_title = Title::newFromText( $term ); - $memckey = wfMemcKey( 'ajaxsearch', md5( $term_title->getFullText() ) ); + $memckey = $term_title ? wfMemcKey( 'ajaxsearch', md5( $term_title->getFullText() ) ) : wfMemcKey( 'ajaxsearch', md5( $term ) ); $cached = $wgMemc->get($memckey); if( is_array( $cached ) && $cached['version'] == AJAX_SEARCH_VERSION ) { $response = new AjaxResponse( $cached['html'] ); Modified: branches/ApiEdit_Vodafone/includes/Article.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Article.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Article.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -1944,7 +1944,7 @@ } $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) ); - + # Better double-check that it hasn't been deleted yet! $dbw = wfGetDB( DB_MASTER ); $conds = $this->mTitle->pageCond(); @@ -1954,6 +1954,17 @@ return; } + # Hack for big sites + $bigHistory = $this->isBigDeletion(); + if( $bigHistory && !$this->mTitle->userCan( 'bigdelete' ) ) { + global $wgLang, $wgDeleteRevisionsLimit; + $wgOut->addWikiText( "<div class='error'>\n" . + wfMsg( 'delete-toobig', + $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) . + "</div>\n" ); + return; + } + if( $confirm ) { $this->doDelete( $reason ); if( $wgRequest->getCheck( 'wpWatch' ) ) { @@ -1972,10 +1983,41 @@ if( $hasHistory && !$confirm ) { $skin=$wgUser->getSkin(); $wgOut->addHTML( '<strong>' . wfMsg( 'historywarning' ) . ' ' . $skin->historyLink() . '</strong>' ); + if( $bigHistory ) { + global $wgLang, $wgDeleteRevisionsLimit; + $wgOut->addWikiText( "<div class='error'>\n" . + wfMsg( 'delete-warning-toobig', + $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) . + "</div>\n" ); + } } return $this->confirmDelete( '', $reason ); } + + /** + * @return bool whether or not the page surpasses $wgDeleteRevisionsLimit revisions + */ + function isBigDeletion() { + global $wgDeleteRevisionsLimit; + if( $wgDeleteRevisionsLimit ) { + $revCount = $this->estimateRevisionCount(); + return $revCount > $wgDeleteRevisionsLimit; + } + return false; + } + + /** + * @return int approximate revision count + */ + function estimateRevisionCount() { + $dbr = wfGetDB(); + // For an exact count... + //return $dbr->selectField( 'revision', 'COUNT(*)', + // array( 'rev_page' => $this->getId() ), __METHOD__ ); + return $dbr->estimateRowCount( 'revision', '*', + array( 'rev_page' => $this->getId() ), __METHOD__ ); + } /** * Get the last N authors @@ -2267,17 +2309,16 @@ * @param string $fromP - Name of the user whose edits to rollback. * @param string $summary - Custom summary. Set to default summary if empty. * @param string $token - Rollback token. - * @param bool $bot - If true, mark all reverted edits as bot. + * @param bool $bot - If true, mark all reverted edits as bot. * * @param array $resultDetails contains result-specific array of additional values * 'alreadyrolled' : 'current' (rev) * success : 'summary' (str), 'current' (rev), 'target' (rev) * - * @return array of errors, each error formatted as array(messagekey, param1, param2, ...). - * On success, the array is empty. This array can also be passed to OutputPage::showPermissionsErrorPage(). - * NOTE: If the user is blocked, 'blocked' is passed as a message, but it doesn't exist. Be sure to check - * it before calling showPermissionsErrorPage(). The same is true for 'actionthrottledtext', which - * is passed if the rate limit is passed. + * @return array of errors, each error formatted as + * array(messagekey, param1, param2, ...). + * On success, the array is empty. This array can also be passed to + * OutputPage::showPermissionsErrorPage(). */ public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails ) { global $wgUser; @@ -2292,9 +2333,6 @@ if ( $wgUser->pingLimiter('rollback') || $wgUser->pingLimiter() ) { $errors[] = array( 'actionthrottledtext' ); } - if ( $wgUser->isBlocked() ) - $errors[] = array( 'blocked' ); - # If there were errors, bail out now if(!empty($errors)) return $errors; @@ -2303,15 +2341,22 @@ } /** - * Backend implementation of doRollback(), please refer there for parameter and return value documentation + * Backend implementation of doRollback(), please refer there for parameter + * and return value documentation * - * NOTE: This function does NOT check ANY permissions, it just commits the rollback to the DB. - * Therefore, you should only call this function directly if you really know what you're doing. If you don't, use doRollback() instead + * NOTE: This function does NOT check ANY permissions, it just commits the + * rollback to the DB Therefore, you should only call this function direct- + * ly if you want to use custom permissions checks. If you don't, use + * doRollback() instead. */ public function commitRollback($fromP, $summary, $bot, &$resultDetails) { - global $wgUseRCPatrol; + global $wgUseRCPatrol, $wgUser; $dbw = wfGetDB( DB_MASTER ); + if( wfReadOnly() ) { + return array( array( 'readonlytext' ) ); + } + # Get the last editor $current = Revision::newFromTitle( $this->mTitle ); if( is_null( $current ) ) { @@ -2411,19 +2456,34 @@ $wgRequest->getBool( 'bot' ), $details ); - - if(in_array(array('blocked'), $result)) { + + if( in_array( array( 'blocked' ), $result ) ) { $wgOut->blockedPage(); return; } - if(in_array(array('actionthrottledtext'), $result)) { + if( in_array( array( 'actionthrottledtext' ), $result ) ) { $wgOut->rateLimited(); return; } - if(!empty($result)) { - $wgOut->showPermissionsErrorPage( $result ); + # Display permissions errors before read-only message -- there's no + # point in misleading the user into thinking the inability to rollback + # is only temporary. + if( !empty($result) && $result !== array( array('readonlytext') ) ) { + # array_diff is completely broken for arrays of arrays, sigh. Re- + # move any 'readonlytext' error manually. + $out = array(); + foreach( $result as $error ) { + if( $error != array( 'readonlytext' ) ) { + $out []= $error; + } + } + $wgOut->showPermissionsErrorPage( $out ); return; } + if( $result == array( array('readonlytext') ) ) { + $wgOut->readOnlyPage(); + return; + } $current = $details['current']; $target = $details['target']; @@ -2496,7 +2556,7 @@ * @param $changed Whether or not the content actually changed */ function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true ) { - global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser; + global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser, $wgEnableParserCache; wfProfileIn( __METHOD__ ); @@ -2511,8 +2571,10 @@ } # Save it to the parser cache - $parserCache =& ParserCache::singleton(); - $parserCache->save( $editInfo->output, $this, $wgUser ); + if ( $wgEnableParserCache ) { + $parserCache =& ParserCache::singleton(); + $parserCache->save( $editInfo->output, $this, $wgUser ); + } # Update the links tables $u = new LinksUpdate( $this->mTitle, $editInfo->output ); @@ -2896,9 +2958,11 @@ global $wgDeferredUpdateList, $wgUseFileCache; // Invalidate caches of articles which include this page - $update = new HTMLCacheUpdate( $title, 'templatelinks' ); - $wgDeferredUpdateList[] = $update; + $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'templatelinks' ); + // Invalidate the caches of all pages which redirect here + $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'redirect' ); + # Purge squid for this page only $title->purgeSquid(); @@ -3123,7 +3187,7 @@ * @param bool $cache */ public function outputWikiText( $text, $cache = true ) { - global $wgParser, $wgUser, $wgOut; + global $wgParser, $wgUser, $wgOut, $wgEnableParserCache; $popts = $wgOut->parserOptions(); $popts->setTidy(true); @@ -3132,7 +3196,7 @@ $popts, true, true, $this->getRevIdFetched() ); $popts->setTidy(false); $popts->enableLimitReport( false ); - if ( $cache && $this && $parserOutput->getCacheTime() != -1 ) { + if ( $wgEnableParserCache && $cache && $this && $parserOutput->getCacheTime() != -1 ) { $parserCache =& ParserCache::singleton(); $parserCache->save( $parserOutput, $this, $wgUser ); } Modified: branches/ApiEdit_Vodafone/includes/CoreParserFunctions.php =================================================================== --- branches/ApiEdit_Vodafone/includes/CoreParserFunctions.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/CoreParserFunctions.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -221,6 +221,13 @@ return ''; } $tagName = strtolower( trim( $frame->expand( array_shift( $args ) ) ) ); + + if ( count( $args ) ) { + $inner = $frame->expand( array_shift( $args ) ); + } else { + $inner = null; + } + $stripList = $parser->getStripList(); if ( !in_array( $tagName, $stripList ) ) { return '<span class="error">' . @@ -228,37 +235,28 @@ '</span>'; } - $lastNumberedNode = false; $attributes = array(); foreach ( $args as $arg ) { if ( !$xpath ) { $xpath = new DOMXPath( $arg->ownerDocument ); } $names = $xpath->query( 'name', $arg ); - if ( $names->item( 0 )->hasAttributes() ) { - $lastNumberedNode = $arg; - } else { + if ( !$names->item( 0 )->hasAttributes() ) { $name = $frame->expand( $names->item( 0 ), PPFrame::STRIP_COMMENTS ); - if ( preg_match( '/^\d+$/', $name ) ) { - // For = suppression syntax {{#tag|thing|1=2=3=4}} - $lastNumberedNode = $arg; - } else { - $values = $xpath->query( 'value', $arg ); - $attributes[$name] = trim( $frame->expand( $values->item( 0 ) ) ); + $values = $xpath->query( 'value', $arg ); + $value = trim( $frame->expand( $values->item( 0 ) ) ); + if ( preg_match( '/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) { + $value = isset( $m[1] ) ? $m[1] : ''; } - } + $attributes[$name] = $value; + } } - if ( !$lastNumberedNode ) { - $inner = null; - } else { - $values = $xpath->query( 'value', $lastNumberedNode ); - $inner = $frame->expand( $values->item( 0 ) ); - } $params = array( 'name' => $tagName, 'inner' => $inner, - 'attributes' => $attributes + 'attributes' => $attributes, + 'close' => "</$tagName>", ); return $parser->extensionSubstitution( $params, $frame ); } Modified: branches/ApiEdit_Vodafone/includes/DefaultSettings.php =================================================================== --- branches/ApiEdit_Vodafone/includes/DefaultSettings.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/DefaultSettings.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -157,6 +157,7 @@ $wgHashedUploadDirectory = true; $wgLogo = false; /// defaults to "{$wgStylePath}/common/images/wiki.png" $wgFavicon = '/favicon.ico'; +$wgAppleTouchIcon = false; /// This one'll actually default to off. For iPhone and iPod Touch web app bookmarks $wgMathPath = false; /// defaults to "{$wgUploadPath}/math" $wgMathDirectory = false; /// defaults to "{$wgUploadDirectory}/math" $wgTmpDirectory = false; /// defaults to "{$wgUploadDirectory}/tmp" @@ -460,7 +461,12 @@ */ $wgRepositoryBaseUrl="http://commons.wikimedia.org/wiki/Image:"; +/** + * Experimental feature still under debugging. + */ +$wgFileRedirects = false; + # # Email settings # @@ -1094,6 +1100,7 @@ $wgGroupPermissions['sysop']['block'] = true; $wgGroupPermissions['sysop']['createaccount'] = true; $wgGroupPermissions['sysop']['delete'] = true; +$wgGroupPermissions['sysop']['bigdelete'] = true; // can be separately configured for pages with > $wgDeleteRevisionsLimit revs $wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text $wgGroupPermissions['sysop']['undelete'] = true; $wgGroupPermissions['sysop']['editinterface'] = true; @@ -1242,6 +1249,12 @@ */ $wgAddGroups = $wgRemoveGroups = array(); +/** + * Optional to restrict deletion of pages with higher revision counts + * to users with the 'bigdelete' permission. (Default given to sysops.) + */ +$wgDeleteRevisionsLimit = 0; + # Proxy scanner settings # Modified: branches/ApiEdit_Vodafone/includes/Defines.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Defines.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Defines.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -262,13 +262,14 @@ # Hook support constants define( 'MW_SUPPORTS_EDITFILTERMERGED', 1 ); +define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 ); # Allowed values for Parser::$mOutputType # Parameter to Parser::startExternalParse(). define( 'OT_HTML', 1 ); define( 'OT_WIKI', 2 ); -define( 'OT_MSG' , 3 ); -define( 'OT_PREPROCESS', 4 ); +define( 'OT_PREPROCESS', 3 ); +define( 'OT_MSG' , 3 ); // b/c alias for OT_PREPROCESS # Flags for Parser::setFunctionHook define( 'SFH_NO_HASH', 1 ); @@ -282,4 +283,4 @@ define( 'APCOND_EDITCOUNT', 1 ); define( 'APCOND_AGE', 2 ); define( 'APCOND_EMAILCONFIRMED', 3 ); -define( 'APCOND_INGROUPS', 4 ); \ No newline at end of file +define( 'APCOND_INGROUPS', 4 ); Modified: branches/ApiEdit_Vodafone/includes/EditPage.php =================================================================== --- branches/ApiEdit_Vodafone/includes/EditPage.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/EditPage.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -38,6 +38,8 @@ const AS_OK = 230; const AS_END = 231; const AS_SPAM_ERROR = 232; + const AS_IMAGE_REDIRECT_ANON = 233; + const AS_IMAGE_REDIRECT_LOGGED = 234; var $mArticle; var $mTitle; @@ -699,6 +701,17 @@ return self::AS_HOOK_ERROR; } + # Check image redirect + if ( $wgTitle->getNamespace() == NS_IMAGE && + Title::newFromRedirect( $this->textbox1 ) instanceof Title && + !$wgUser->isAllowed( 'upload' ) ) { + if( $wgUser->isAnon() ) { + return self::AS_IMAGE_REDIRECT_ANON; + } else { + return self::AS_IMAGE_REDIRECT_LOGGED; + } + } + # Reintegrate metadata if ( $this->mMetaData != '' ) $this->textbox1 .= "\n" . $this->mMetaData ; $this->mMetaData = '' ; @@ -2196,6 +2209,10 @@ $this->blockedPage(); return false; + case self::AS_IMAGE_REDIRECT_ANON: + $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' ); + return false; + case self::AS_READ_ONLY_PAGE_ANON: $this->userNotLoggedInPage(); return false; @@ -2216,6 +2233,10 @@ case self::AS_BLANK_ARTICLE: $wgOut->redirect( $wgTitle->getFullURL() ); return false; + + case self::AS_IMAGE_REDIRECT_LOGGED: + $wgOut->permissionRequired( 'upload' ); + return false; } } } Modified: branches/ApiEdit_Vodafone/includes/ExternalEdit.php =================================================================== --- branches/ApiEdit_Vodafone/includes/ExternalEdit.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/ExternalEdit.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -34,6 +34,7 @@ $name=$this->mTitle->getText(); $pos=strrpos($name,".")+1; header ( "Content-type: application/x-external-editor; charset=".$this->mCharset ); + header( "Cache-control: no-cache" ); # $type can be "Edit text", "Edit file" or "Diff text" at the moment # See the protocol specifications at [[m:Help:External editors/Tech]] for Modified: branches/ApiEdit_Vodafone/includes/GlobalFunctions.php =================================================================== --- branches/ApiEdit_Vodafone/includes/GlobalFunctions.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/GlobalFunctions.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -427,24 +427,12 @@ function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) { global $wgParser, $wgContLang, $wgMessageCache, $wgLang; - /* <Vyznev> btw, is all that code in wfMsgGetKey() that check - * if the message cache exists of not really necessary, or is - * it just paranoia? - * <TimStarling> Vyznev: it's probably not necessary - * <TimStarling> I think I wrote it in an attempt to report DB - * connection errors properly - * <TimStarling> but eventually we gave up on using the - * message cache for that and just hard-coded the strings - * <TimStarling> it may have other uses, it's not mere paranoia - */ - - if ( is_object( $wgMessageCache ) ) - $transstat = $wgMessageCache->getTransform(); - + # If $wgMessageCache isn't initialised yet, try to return something sensible. if( is_object( $wgMessageCache ) ) { - if ( ! $transform ) - $wgMessageCache->disableTransform(); $message = $wgMessageCache->get( $key, $useDB, $forContent ); + if ( $transform ) { + $message = $wgMessageCache->transform( $message ); + } } else { if( $forContent ) { $lang = &$wgContLang; @@ -456,22 +444,13 @@ # ISSUE: Should we try to handle "message/lang" here too? $key = str_replace( ' ' , '_' , $wgContLang->lcfirst( $key ) ); - wfSuppressWarnings(); if( is_object( $lang ) ) { $message = $lang->getMessage( $key ); } else { $message = false; } - wfRestoreWarnings(); - - if ( $transform && strstr( $message, '{{' ) !== false ) { - $message = $wgParser->transformMsg($message, $wgMessageCache->getParserOptions() ); - } } - if ( is_object( $wgMessageCache ) && ! $transform ) - $wgMessageCache->setTransform( $transstat ); - return $message; } Modified: branches/ApiEdit_Vodafone/includes/HTMLCacheUpdate.php =================================================================== --- branches/ApiEdit_Vodafone/includes/HTMLCacheUpdate.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/HTMLCacheUpdate.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -25,6 +25,7 @@ { public $mTitle, $mTable, $mPrefix; public $mRowsPerJob, $mRowsPerQuery; + public $mResult; function __construct( $titleTo, $table ) { global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery; @@ -40,15 +41,14 @@ $cond = $this->getToCondition(); $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( $this->mTable, $this->getFromField(), $cond, __METHOD__ ); - $resWrap = new ResultWrapper( $dbr, $res ); + $this->mResult = $res; if ( $dbr->numRows( $res ) != 0 ) { if ( $dbr->numRows( $res ) > $this->mRowsPerJob ) { - $this->insertJobs( $resWrap ); + $this->insertJobs( $res ); } else { - $this->invalidateIDs( $resWrap ); + $this->invalidateIDs( $res ); } } - $dbr->freeResult( $res ); } function insertJobs( ResultWrapper $res ) { @@ -87,6 +87,7 @@ 'imagelinks' => 'il', 'categorylinks' => 'cl', 'templatelinks' => 'tl', + 'redirect' => 'rd', # Not needed # 'externallinks' => 'el', @@ -107,17 +108,15 @@ } function getToCondition() { + $prefix = $this->getPrefix(); switch ( $this->mTable ) { case 'pagelinks': + case 'templatelinks': + case 'redirect': return array( - 'pl_namespace' => $this->mTitle->getNamespace(), - 'pl_title' => $this->mTitle->getDBkey() + "{$prefix}_namespace" => $this->mTitle->getNamespace(), + "{$prefix}_title" => $this->mTitle->getDBkey() ); - case 'templatelinks': - return array( - 'tl_namespace' => $this->mTitle->getNamespace(), - 'tl_title' => $this->mTitle->getDBkey() - ); case 'imagelinks': return array( 'il_to' => $this->mTitle->getDBkey() ); case 'categorylinks': @@ -218,7 +217,6 @@ $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( $this->table, $fromField, $conds, __METHOD__ ); $update->invalidateIDs( new ResultWrapper( $dbr, $res ) ); - $dbr->freeResult( $res ); return true; } Modified: branches/ApiEdit_Vodafone/includes/ImagePage.php =================================================================== --- branches/ApiEdit_Vodafone/includes/ImagePage.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/ImagePage.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -411,25 +411,23 @@ $sk = $wgUser->getSkin(); - $line = $this->img->nextHistoryLine(); - - if ( $line ) { + if ( $this->img->exists() ) { $list = new ImageHistoryList( $sk, $this->img ); - $file = $this->repo->newFileFromRow( $line ); + $file = $this->img; $dims = $file->getDimensionsString(); $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, + $list->imageHistoryLine( true, wfTimestamp(TS_MW, $file->getTimestamp()), + $this->mTitle->getDBkey(), $file->getUser('id'), + $file->getUser('text'), $file->getSize(), $file->getDescription(), $dims ); - while ( $line = $this->img->nextHistoryLine() ) { - $file = $this->repo->newFileFromRow( $line ); + $hist = $this->img->getHistory(); + foreach( $hist as $file ) { $dims = $file->getDimensionsString(); - $s .= $list->imageHistoryLine( false, $line->oi_timestamp, - $line->oi_archive_name, $line->oi_user, - $line->oi_user_text, $line->oi_size, $line->oi_description, + $s .= $list->imageHistoryLine( false, wfTimestamp(TS_MW, $file->getTimestamp()), + $file->getArchiveName(), $file->getUser('id'), + $file->getUser('text'), $file->getSize(), $file->getDescription(), $dims ); } Modified: branches/ApiEdit_Vodafone/includes/Linker.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Linker.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Linker.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -723,6 +723,10 @@ $upload = SpecialPage::getTitleFor( 'Upload' ); if( $text == '' ) $text = htmlspecialchars( $title->getPrefixedText() ); + $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title ); + if( $redir ) { + return $this->makeKnownLinkObj( $title, $text, $query, $trail, $prefix ); + } $q = 'wpDestFile=' . $title->getPartialUrl(); if( $query != '' ) $q .= '&' . $query; Modified: branches/ApiEdit_Vodafone/includes/MessageCache.php =================================================================== --- branches/ApiEdit_Vodafone/includes/MessageCache.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/MessageCache.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -500,9 +500,6 @@ if( $message === false ) { return '<' . htmlspecialchars($key) . '>'; } - - # Replace brace tags - $message = $this->transform( $message ); return $message; } @@ -584,12 +581,11 @@ # Clone it and store it $this->mParser = clone $wgParser; } - if ( !$this->mDisableTransform && $this->mParser ) { + if ( $this->mParser ) { if( strpos( $message, '{{' ) !== false ) { $popts = $this->getParserOptions(); - if ( $interface ) { $popts->setInterfaceMessage(true); } + $popts->setInterfaceMessage( $interface ); $message = $this->mParser->transformMsg( $message, $popts ); - if ( $interface ) { $popts->setInterfaceMessage(false); } } } return $message; @@ -597,11 +593,13 @@ function disable() { $this->mDisable = true; } function enable() { $this->mDisable = false; } - function disableTransform() { $this->mDisableTransform = true; } - function enableTransform() { $this->mDisableTransform = false; } - function setTransform( $x ) { $this->mDisableTransform = $x; } - function getTransform() { return $this->mDisableTransform; } + /** @deprecated */ + function disableTransform() {} + function enableTransform() {} + function setTransform( $x ) {} + function getTransform() { return false; } + /** * Add a message to the cache * Modified: branches/ApiEdit_Vodafone/includes/Parser.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Parser.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Parser.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -15,15 +15,17 @@ * (which in turn the browser understands, and can display). * * <pre> - * There are four main entry points into the Parser class: + * There are five main entry points into the Parser class: * parse() * produces HTML output * preSaveTransform(). * produces altered wiki markup. - * transformMsg() - * performs brace substitution on MediaWiki messages * preprocess() * removes HTML comments and expands templates + * cleanSig() + * Cleans a signature before saving it to preferences + * extractSections() + * Extracts sections from an article for section editing * * Globals used: * objects: $wgLang, $wgContLang @@ -126,6 +128,7 @@ if ( !$this->mFirstCall ) { return; } + $this->mFirstCall = false; wfProfileIn( __METHOD__ ); global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; @@ -174,7 +177,8 @@ } $this->initialiseVariables(); - $this->mFirstCall = false; + + wfRunHooks( 'ParserFirstCallInit', array( &$this ) ); wfProfileOut( __METHOD__ ); } @@ -245,12 +249,27 @@ $this->ot = array( 'html' => $ot == OT_HTML, 'wiki' => $ot == OT_WIKI, - 'msg' => $ot == OT_MSG, 'pre' => $ot == OT_PREPROCESS, ); } /** + * Set the context title + */ + function setTitle( $t ) { + if ( !$t || $t instanceof FakeTitle ) { + $t = Title::newFromText( 'NO TITLE' ); + } + if ( strval( $t->getFragment() ) !== '' ) { + # Strip the fragment to avoid various odd effects + $this->mTitle = clone $t; + $this->mTitle->setFragment( '' ); + } else { + $this->mTitle = $t; + } + } + + /** * Accessor for mUniqPrefix. * * @public @@ -296,7 +315,7 @@ } $this->mOptions = $options; - $this->mTitle =& $title; + $this->setTitle( $title ); $oldRevisionId = $this->mRevisionId; $oldRevisionTimestamp = $this->mRevisionTimestamp; if( $revid !== null ) { @@ -393,6 +412,7 @@ if ( $this->mOptions->getEnableLimitReport() ) { $max = $this->mOptions->getMaxIncludeSize(); $limitReport = + "NewPP limit report\n" . "Preprocessor node count: {$this->mPPNodeCount}/{$this->mOptions->mMaxPPNodeCount}\n" . "Post-expand include size: {$this->mIncludeSizes['post-expand']}/$max bytes\n" . "Template argument size: {$this->mIncludeSizes['arg']}/$max bytes\n"; @@ -430,16 +450,13 @@ $this->clearState(); $this->setOutputType( OT_PREPROCESS ); $this->mOptions = $options; - $this->mTitle = $title; + $this->setTitle( $title ); if( $revid !== null ) { $this->mRevisionId = $revid; } wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) ); wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) ); $text = $this->replaceVariables( $text ); - if ( $this->mOptions->getRemoveComments() ) { - $text = Sanitizer::removeHTMLcomments( $text ); - } $text = $this->mStripState->unstripBoth( $text ); wfProfileOut( __METHOD__ ); return $text; @@ -2565,7 +2582,7 @@ * self::PTD_FOR_INCLUSION Handle <noinclude>/<includeonly> as if the text is being * included. Default is to assume a direct page view. * - * The generated DOM tree must depend only on the input text, the flags, and $this->ot['msg']. + * The generated DOM tree must depend only on the input text and the flags. * The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899. * * Any flag added to the $flags parameter here, or any other parameter liable to cause a @@ -2582,47 +2599,24 @@ wfProfileIn( __METHOD__ ); wfProfileIn( __METHOD__.'-makexml' ); - static $msgRules, $normalRules, $inclusionSupertags, $nonInclusionSupertags; - if ( !$msgRules ) { - $msgRules = array( - '{' => array( - 'end' => '}', - 'names' => array( - 2 => 'template', - ), - 'min' => 2, - 'max' => 2, + $rules = array( + '{' => array( + 'end' => '}', + 'names' => array( + 2 => 'template', + 3 => 'tplarg', ), - '[' => array( - 'end' => ']', - 'names' => array( 2 => null ), - 'min' => 2, - 'max' => 2, - ) - ); - $normalRules = array( - '{' => array( - 'end' => '}', - 'names' => array( - 2 => 'template', - 3 => 'tplarg', - ), - 'min' => 2, - 'max' => 3, - ), - '[' => array( - 'end' => ']', - 'names' => array( 2 => null ), - 'min' => 2, - 'max' => 2, - ) - ); - } - if ( $this->ot['msg'] ) { - $rules = $msgRules; - } else { - $rules = $normalRules; - } + 'min' => 2, + 'max' => 3, + ), + '[' => array( + 'end' => ']', + 'names' => array( 2 => null ), + 'min' => 2, + 'max' => 2, + ) + ); + $forInclusion = $flags & self::PTD_FOR_INCLUSION; $xmlishElements = $this->getStripList(); @@ -2644,19 +2638,18 @@ // Use "A" modifier (anchored) instead of "^", because ^ doesn't work with an offset $elementsRegex = "~($xmlishRegex)(?:\s|\/>|>)|(!--)~iA"; - $stack = array(); # Stack of unclosed parentheses - $stackIndex = -1; # Stack read pointer + $stack = new PPDStack; - $searchBase = implode( '', array_keys( $rules ) ) . '<'; + $searchBase = '[.{<'; $revText = strrev( $text ); // For fast reverse searches $i = 0; # Input pointer, starts out pointing to a pseudo-newline before the start - $topAccum = '<root>'; # Top level text accumulator - $accum =& $topAccum; # Current text accumulator + $accum =& $stack->getAccum(); # Current text accumulator + $accum = '<root>'; $findEquals = false; # True to find equals signs in arguments - $findHeading = false; # True to look at LF characters for possible headings $findPipe = false; # True to take notice of pipe characters $headingIndex = 1; + $inHeading = false; # True if $i is inside a possible heading $noMoreGT = false; # True if there are no more greater-than (>) signs right of $i $findOnlyinclude = $enableOnlyinclude; # True to ignore all input up to the next <onlyinclude> $fakeLineStart = true; # Do a line-start run without outputting an LF character @@ -2682,21 +2675,29 @@ } else { # Find next opening brace, closing brace or pipe $search = $searchBase; - if ( $stackIndex == -1 ) { + if ( $stack->top === false ) { $currentClosing = ''; - // Look for headings only at the top stack level - // Among other things, this resolves the ambiguity between = - // for headings and = for template arguments - $search .= "\n"; } else { - $currentClosing = $stack[$stackIndex]['close']; + $currentClosing = $stack->top->close; $search .= $currentClosing; } if ( $findPipe ) { $search .= '|'; } if ( $findEquals ) { + // First equals will be for the template $search .= '='; + } else { + // Look for headings + // We can't look for headings when $findEquals is true, because the ambiguity + // between template name/value separators and heading starts would be unresolved + // until the closing double-brace is found. This would mean either infinite + // backtrack, or creating and updating two separate tree structures until the + // end of the ambiguity -- one tree structure assuming a heading, and the other + // assuming a template argument. + // + // Easier to just break some section edit links. + $search .= "\n"; } $rule = null; # Output literal section, advance input counter @@ -2723,10 +2724,10 @@ } elseif ( $curChar == '<' ) { $found = 'angle'; } elseif ( $curChar == "\n" ) { - if ( $stackIndex == -1 ) { + if ( $inHeading ) { + $found = 'line-end'; + } else { $found = 'line-start'; - } else { - $found = 'line-end'; } } elseif ( $curChar == $currentClosing ) { $found = 'close'; @@ -2792,8 +2793,8 @@ $accum = substr( $accum, 0, -$wsLength ); } // Do a line-start run next time to look for headings after the comment, - // but only if stackIndex=-1, because headings don't exist at deeper levels. - if ( $stackIndex == -1 ) { + // but only if stack->top===false, because headings don't exist at deeper levels. + if ( $stack->top === false ) { $fakeLineStart = true; } } else { @@ -2890,27 +2891,32 @@ 'parts' => array( str_repeat( '=', $count ) ), 'startPos' => $i, 'count' => $count ); - $stack[++$stackIndex] = $piece; + $stack->push( $piece ); + $accum =& $stack->getAccum(); + extract( $stack->getFlags() ); $i += $count; - $accum =& $stack[$stackIndex]['parts'][0]; - $findPipe = false; } } elseif ( $found == 'line-end' ) { - $piece = $stack[$stackIndex]; + $piece = $stack->top; // A heading must be open, otherwise \n wouldn't have been in the search list - assert( $piece['open'] == "\n" ); - assert( $stackIndex == 0 ); + assert( $piece->open == "\n" ); // Search back through the input to see if it has a proper close // Do this using the reversed string since the other solutions (end anchor, etc.) are inefficient $m = false; - $count = $piece['count']; - if ( preg_match( "/\s*(={{$count}})/A", $revText, $m, 0, strlen( $text ) - $i ) ) { - if ( $i - strlen( $m[0] ) == $piece['startPos'] ) { + $count = $piece->count; + if ( preg_match( "/\s*(=+)/A", $revText, $m, 0, strlen( $text ) - $i ) ) { + if ( $i - strlen( $m[0] ) == $piece->startPos ) { // This is just a single string of equals signs on its own line - // Divide by two and round down to create start and end delimiters - $count = intval( $count / 2 ); + // Replicate the doHeadings behaviour /={count}(.+)={count}/ + // First find out how many equals signs there really are (don't stop at 6) + $count = strlen( $m[1] ); + if ( $count < 3 ) { + $count = 0; + } else { + $count = min( 6, intval( ( $count - 1 ) / 2 ) ); + } } else { $count = min( strlen( $m[1] ), $count ); } @@ -2927,12 +2933,9 @@ $element = $accum; } // Unwind the stack - // Headings can only occur on the top level, so this is a bit simpler than the - // generic stack unwind operation in the close case - unset( $stack[$stackIndex--] ); - $accum =& $topAccum; - $findEquals = false; - $findPipe = false; + $stack->pop(); + $accum =& $stack->getAccum(); + extract( $stack->getFlags() ); // Append the result to the enclosing accumulator $accum .= $element; @@ -2959,11 +2962,9 @@ 'lineStart' => ($i > 0 && $text[$i-1] == "\n"), ); - $stackIndex ++; - $stack[$stackIndex] = $piece; - $accum =& $stack[$stackIndex]['parts'][0]; - $findEquals = false; - $findPipe = true; + $stack->push( $piece ); + $accum =& $stack->getAccum(); + extract( $stack->getFlags() ); } else { # Add literal brace(s) $accum .= htmlspecialchars( str_repeat( $curChar, $count ) ); @@ -2972,15 +2973,15 @@ } elseif ( $found == 'close' ) { - $piece = $stack[$stackIndex]; + $piece = $stack->top; # lets check if there are enough characters for closing brace - $maxCount = $piece['count']; + $maxCount = $piece->count; $count = strspn( $text, $curChar, $i, $maxCount ); # check for maximum matching characters (if there are 5 closing # characters, we will probably need only 3 - depending on the rules) $matchingCount = 0; - $rule = $rules[$piece['open']]; + $rule = $rules[$piece->open]; if ( $count > $rule['max'] ) { # The specified maximum exists in the callback array, unless the caller # has made an error @@ -3005,19 +3006,19 @@ $name = $rule['names'][$matchingCount]; if ( $name === null ) { // No element, just literal text - $element = str_repeat( $piece['open'], $matchingCount ) . - implode( '|', $piece['parts'] ) . + $element = str_repeat( $piece->open, $matchingCount ) . + implode( '|', $piece->parts ) . str_repeat( $rule['end'], $matchingCount ); } else { # Create XML element # Note: $parts is already XML, does not need to be encoded further - $parts = $piece['parts']; + $parts = $piece->parts; $title = $parts[0]; unset( $parts[0] ); # The invocation is at the start of the line if lineStart is set in # the stack, and all opening brackets are used up. - if ( $maxCount == $matchingCount && !empty( $piece['lineStart'] ) ) { + if ( $maxCount == $matchingCount && !empty( $piece->lineStart ) ) { $attr = ' lineStart="1"'; } else { $attr = ''; @@ -3027,8 +3028,8 @@ $element .= "<title>$title</title>"; $argIndex = 1; foreach ( $parts as $partIndex => $part ) { - if ( isset( $piece['eqpos'][$partIndex] ) ) { - $eqpos = $piece['eqpos'][$partIndex]; + if ( isset( $piece->eqpos[$partIndex] ) ) { + $eqpos = $piece->eqpos[$partIndex]; $argName = substr( $part, 0, $eqpos ); $argValue = substr( $part, $eqpos + 1 ); $element .= "<part><name>$argName</name>=<value>$argValue</value></part>"; @@ -3044,84 +3045,73 @@ $i += $matchingCount; # Unwind the stack - unset( $stack[$stackIndex--] ); - if ( $stackIndex == -1 ) { - $accum =& $topAccum; - $findEquals = false; - $findPipe = false; - } else { - $partCount = count( $stack[$stackIndex]['parts'] ); - $accum =& $stack[$stackIndex]['parts'][$partCount - 1]; - $findPipe = $stack[$stackIndex]['open'] != "\n"; - $findEquals = $findPipe && $partCount > 1 - && !isset( $stack[$stackIndex]['eqpos'][$partCount - 1] ); - } + $stack->pop(); + $accum =& $stack->getAccum(); # Re-add the old stack element if it still has unmatched opening characters remaining - if ($matchingCount < $piece['count']) { - $piece['parts'] = array( '' ); - $piece['count'] -= $matchingCount; - $piece['eqpos'] = array(); + if ($matchingCount < $piece->count) { + $piece->parts = array( '' ); + $piece->count -= $matchingCount; + $piece->eqpos = array(); # do we still qualify for any callback with remaining count? - $names = $rules[$piece['open']]['names']; + $names = $rules[$piece->open]['names']; $skippedBraces = 0; $enclosingAccum =& $accum; - while ( $piece['count'] ) { - if ( array_key_exists( $piece['count'], $names ) ) { - $stackIndex++; - $stack[$stackIndex] = $piece; - $accum =& $stack[$stackIndex]['parts'][0]; - $findEquals = true; - $findPipe = true; + while ( $piece->count ) { + if ( array_key_exists( $piece->count, $names ) ) { + $stack->push( $piece ); + $accum =& $stack->getAccum(); break; } - --$piece['count']; + --$piece->count; $skippedBraces ++; } - $enclosingAccum .= str_repeat( $piece['open'], $skippedBraces ); + $enclosingAccum .= str_repeat( $piece->open, $skippedBraces ); } + extract( $stack->getFlags() ); + # Add XML element to the enclosing accumulator $accum .= $element; } elseif ( $found == 'pipe' ) { - $stack[$stackIndex]['parts'][] = ''; - $partsCount = count( $stack[$stackIndex]['parts'] ); - $accum =& $stack[$stackIndex]['parts'][$partsCount - 1]; - $findEquals = true; + $findEquals = true; // shortcut for getFlags() + $stack->top->addPart(); + $accum =& $stack->getAccum(); ++$i; - } + } elseif ( $found == 'equals' ) { - $findEquals = false; - $partsCount = count( $stack[$stackIndex]['parts'] ); - $stack[$stackIndex]['eqpos'][$partsCount - 1] = strlen( $accum ); + $findEquals = false; // shortcut for getFlags() + $partsCount = count( $stack->top->parts ); + $stack->top->eqpos[$partsCount - 1] = strlen( $accum ); $accum .= '='; ++$i; } } # Output any remaining unclosed brackets - foreach ( $stack as $piece ) { - if ( $piece['open'] == "\n" ) { - $topAccum .= $piece['parts'][0]; + foreach ( $stack->stack as $piece ) { + if ( $piece->open == "\n" ) { + $stack->topAccum .= $piece->parts[0]; } else { - $topAccum .= str_repeat( $piece['open'], $piece['count'] ) . implode( '|', $piece['parts'] ); + $stack->topAccum .= str_repeat( $piece->open, $piece->count ) . implode( '|', $piece->parts ); } } - $topAccum .= '</root>'; + $stack->topAccum .= '</root>'; + $xml = $stack->topAccum; wfProfileOut( __METHOD__.'-makexml' ); wfProfileIn( __METHOD__.'-loadXML' ); $dom = new DOMDocument; wfSuppressWarnings(); - $result = $dom->loadXML( $topAccum ); + $result = $dom->loadXML( $xml ); wfRestoreWarnings(); if ( !$result ) { // Try running the XML through UtfNormal to get rid of invalid characters - $topAccum = UtfNormal::cleanUp( $topAccum ); - $result = $dom->loadXML( $topAccum ); + $xml = UtfNormal::cleanUp( $xml ); + $result = $dom->loadXML( $xml ); if ( !$result ) { throw new MWException( __METHOD__.' generated invalid XML' ); } @@ -3154,8 +3144,8 @@ * * Note that the substitution depends on value of $mOutputType: * OT_WIKI: only {{subst:}} templates - * OT_MSG: only magic variables - * OT_HTML: all templates and magic variables + * OT_PREPROCESS: templates but not extension tags + * OT_HTML: all templates and extension tags * * @param string $tex The text to transform * @param PPFrame $frame Object describing the arguments passed to the template @@ -3727,6 +3717,15 @@ } } } else { + if ( is_null( $attrText ) ) { + $attrText = ''; + } + if ( isset( $params['attributes'] ) ) { + foreach ( $params['attributes'] as $attrName => $attrValue ) { + $attrText .= ' ' . htmlspecialchars( $attrName ) . '="' . + htmlspecialchars( $attrValue ) . '"'; + } + } if ( $content === null ) { $output = "<$name$attrText/>"; } else { @@ -4088,7 +4087,7 @@ */ function preSaveTransform( $text, &$title, $user, $options, $clearState = true ) { $this->mOptions = $options; - $this->mTitle =& $title; + $this->setTitle( $title ); $this->setOutputType( OT_WIKI ); if ( $clearState ) { @@ -4238,7 +4237,10 @@ function cleanSig( $text, $parsing = false ) { if ( !$parsing ) { global $wgTitle; - $this->startExternalParse( $wgTitle, new ParserOptions(), OT_MSG ); + $this->clearState(); + $this->setTitle( $wgTitle ); + $this->mOptions = new ParserOptions; + $this->setOutputType = OT_PREPROCESS; } # FIXME: regex doesn't respect extension tags or nowiki @@ -4276,7 +4278,7 @@ * @public */ function startExternalParse( &$title, $options, $outputType, $clearState = true ) { - $this->mTitle =& $title; + $this->setTitle( $title ); $this->mOptions = $options; $this->setOutputType( $outputType ); if ( $clearState ) { @@ -4285,16 +4287,11 @@ } /** - * Transform a MediaWiki message by replacing magic variables. + * Wrapper for preprocess() * - * For some unknown reason, it also expands templates, but only to the - * first recursion level. This is wrong and broken, probably introduced - * accidentally during refactoring, but probably relied upon by thousands - * of users. - * - * @param string $text the text to transform + * @param string $text the text to preprocess * @param ParserOptions $options options - * @return string the text with variables substituted + * @return string * @public */ function transformMsg( $text, $options ) { @@ -4310,18 +4307,8 @@ $executing = true; wfProfileIn($fname); + $text = $this->preprocess( $text, $wgTitle, $options ); - if ( $wgTitle && !( $wgTitle instanceof FakeTitle ) ) { - $this->mTitle = $wgTitle; - } else { - $this->mTitle = Title::newFromText('msg'); - } - $this->mOptions = $options; - $this->setOutputType( OT_MSG ); - $this->clearState(); - $text = $this->replaceVariables( $text ); - $text = $this->mStripState->unstripBoth( $text ); - $executing = false; wfProfileOut($fname); return $text; @@ -5034,7 +5021,7 @@ private function extractSections( $text, $section, $mode, $newText='' ) { global $wgTitle; $this->clearState(); - $this->mTitle = $wgTitle; // not generally used but removes an ugly failure mode + $this->setTitle( $wgTitle ); // not generally used but removes an ugly failure mode $this->mOptions = new ParserOptions; $this->setOutputType( OT_WIKI ); $curIndex = 0; @@ -5270,22 +5257,6 @@ * @todo document, briefly. * @addtogroup Parser */ -class OnlyIncludeReplacer { - var $output = ''; - - function replace( $matches ) { - if ( substr( $matches[1], -1 ) == "\n" ) { - $this->output .= substr( $matches[1], 0, -1 ); - } else { - $this->output .= $matches[1]; - } - } -} - -/** - * @todo document, briefly. - * @addtogroup Parser - */ class StripState { var $general, $nowiki; @@ -5327,6 +5298,22 @@ } /** + * @todo document, briefly. + * @addtogroup Parser + */ +class OnlyIncludeReplacer { + var $output = ''; + + function replace( $matches ) { + if ( substr( $matches[1], -1 ) == "\n" ) { + $this->output .= substr( $matches[1], 0, -1 ); + } else { + $this->output .= $matches[1]; + } + } +} + +/** * An expansion frame, used as a context to expand the result of preprocessToDom() */ class PPFrame { @@ -5409,22 +5396,16 @@ return $root; } - if ( $this->parser->ot['html'] - && ++$this->parser->mPPNodeCount > $this->parser->mOptions->mMaxPPNodeCount ) + if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->mMaxPPNodeCount ) { - return $this->parser->insertStripItem( '<!-- node-count limit exceeded -->' ); + return '<span class="error">Node-count limit exceeded</span>'; } - if ( is_array( $root ) ) { + if ( is_array( $root ) || $root instanceof DOMNodeList ) { $s = ''; foreach ( $root as $node ) { $s .= $this->expand( $node, $flags ); } - } elseif ( $root instanceof DOMNodeList ) { - $s = ''; - foreach ( $root as $node ) { - $s .= $this->expand( $node, $flags ); - } } elseif ( $root instanceof DOMNode ) { if ( $root->nodeType == XML_TEXT_NODE ) { $s = $root->nodeValue; @@ -5451,7 +5432,7 @@ $titles = $xpath->query( 'title', $root ); $title = $titles->item( 0 ); $parts = $xpath->query( 'part', $root ); - if ( $flags & self::NO_ARGS || $this->parser->ot['msg'] ) { + if ( $flags & self::NO_ARGS ) { $s = '{{{' . $this->implodeWithFlags( '|', $flags, $title, $parts ) . '}}}'; } else { $params = array( 'title' => $title, 'parts' => $parts, 'text' => 'FIXME' ); @@ -5693,7 +5674,6 @@ } function getArgument( $name ) { - wfDebug( __METHOD__." getting '$name'\n" ); $text = $this->getNumberedArgument( $name ); if ( $text === false ) { $text = $this->getNamedArgument( $name ); @@ -5701,3 +5681,88 @@ return $text; } } + +/** + * Stack class to help Parser::preprocessToDom() + */ +class PPDStack { + var $stack, $topAccum, $top; + + function __construct() { + $this->stack = array(); + $this->topAccum = ''; + $this->top = false; + } + + function &getAccum() { + if ( count( $this->stack ) ) { + return $this->top->getAccum(); + } else { + return $this->topAccum; + } + } + + function push( $data ) { + if ( $data instanceof PPDStackElement ) { + $this->stack[] = $data; + } else { + $this->stack[] = new PPDStackElement( $data ); + } + $this->top =& $this->stack[ count( $this->stack ) - 1 ]; + } + + function pop() { + if ( !count( $this->stack ) ) { + throw new MWException( __METHOD__.': no elements remaining' ); + } + $temp = array_pop( $this->stack ); + if ( count( $this->stack ) ) { + $this->top =& $this->stack[ count( $this->stack ) - 1 ]; + } else { + $this->top = false; + } + } + + function getFlags() { + if ( !count( $this->stack ) ) { + return array( + 'findEquals' => false, + 'findPipe' => false, + 'inHeading' => false, + ); + } else { + return $this->top->getFlags(); + } + } +} + +class PPDStackElement { + var $open, $close, $count, $parts, $eqpos, $lineStart; + + function __construct( $data = array() ) { + $this->parts = array( '' ); + $this->eqpos = array(); + + foreach ( $data as $name => $value ) { + $this->$name = $value; + } + } + + function &getAccum() { + return $this->parts[count($this->parts) - 1]; + } + + function addPart( $s = '' ) { + $this->parts[] = $s; + } + + function getFlags() { + $partCount = count( $this->parts ); + $findPipe = $this->open != "\n" && $this->open != '[.'; + return array( + 'findPipe' => $findPipe, + 'findEquals' => $findPipe && $partCount > 1 && !isset( $this->eqpos[$partCount - 1] ), + 'inHeading' => $this->open == "\n", + ); + } +} Modified: branches/ApiEdit_Vodafone/includes/Parser_OldPP.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Parser_OldPP.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Parser_OldPP.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -81,6 +81,7 @@ if ( !$this->mFirstCall ) { return; } + $this->mFirstCall = false; wfProfileIn( __METHOD__ ); global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; @@ -128,7 +129,8 @@ } $this->initialiseVariables(); - $this->mFirstCall = false; + + wfRunHooks( 'ParserFirstCallInit', array( &$this ) ); wfProfileOut( __METHOD__ ); } @@ -3829,7 +3831,7 @@ */ function getUserSig( &$user ) { global $wgMaxSigChars; - + $username = $user->getName(); $nickname = $user->getOption( 'nickname' ); $nickname = $nickname === '' ? $username : $nickname; @@ -3884,7 +3886,7 @@ */ function cleanSig( $text, $parsing = false ) { global $wgTitle; - $this->startExternalParse( $wgTitle, new ParserOptions(), $parsing ? OT_WIKI : OT_MSG ); + $this->startExternalParse( $this->mTitle, new ParserOptions(), $parsing ? OT_WIKI : OT_MSG ); $substWord = MagicWord::get( 'subst' ); $substRegex = '/\{\{(?!(?:' . $substWord->getBaseRegex() . '))/x' . $substWord->getRegexCase(); Modified: branches/ApiEdit_Vodafone/includes/RawPage.php =================================================================== --- branches/ApiEdit_Vodafone/includes/RawPage.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/RawPage.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -126,8 +126,7 @@ $url = $_SERVER['PHP_SELF']; } - $ua = @$_SERVER['HTTP_USER_AGENT']; - if( strcmp( $wgScript, $url ) && strpos( $ua, 'MSIE' ) !== false ) { + if( strcmp( $wgScript, $url ) ) { # Internet Explorer will ignore the Content-Type header if it # thinks it sees a file extension it recognizes. Make sure that # all raw requests are done through the script node, which will Modified: branches/ApiEdit_Vodafone/includes/SiteConfiguration.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SiteConfiguration.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SiteConfiguration.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -36,11 +36,25 @@ if ( !is_null( $retval ) && count( $params ) ) { foreach ( $params as $key => $value ) { - $retval = str_replace( '$' . $key, $value, $retval ); + $retval = $this->doReplace( '$' . $key, $value, $retval ); } } return $retval; } + + /** Type-safe string replace; won't do replacements on non-strings */ + function doReplace( $from, $to, $in ) { + if( is_string( $in ) ) { + return str_replace( $from, $to, $in ); + } elseif( is_array( $in ) ) { + foreach( $in as $key => $val ) { + $in[$key] = $this->doReplace( $from, $to, $val ); + } + return $in; + } else { + return $in; + } + } /** */ function getAll( $wiki, $suffix, $params ) { Modified: branches/ApiEdit_Vodafone/includes/Skin.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Skin.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Skin.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -153,13 +153,17 @@ } function initPage( &$out ) { - global $wgFavicon, $wgScriptPath, $wgSitename, $wgContLang; + global $wgFavicon, $wgAppleTouchIcon, $wgScriptPath, $wgSitename, $wgContLang; wfProfileIn( __METHOD__ ); if( false !== $wgFavicon ) { $out->addLink( array( 'rel' => 'shortcut icon', 'href' => $wgFavicon ) ); } + + if( false !== $wgAppleTouchIcon ) { + $out->addLink( array( 'rel' => 'apple-touch-icon', 'href' => $wgAppleTouchIcon ) ); + } $code = $wgContLang->getCode(); $name = $wgContLang->getLanguageName( $code ); Modified: branches/ApiEdit_Vodafone/includes/SpecialBlockip.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialBlockip.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialBlockip.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -282,17 +282,10 @@ } } - const BLOCK_SUCCESS = 0; // Success - const BLOCK_RANGE_INVALID = 1; // Invalid IP range - const BLOCK_RANGE_DISABLED = 2; // Sysops can't block ranges - const BLOCK_NONEXISTENT_USER = 3; // No such user - const BLOCK_IP_INVALID = 4; // Invalid IP address - const BLOCK_EXPIRY_INVALID = 5; // Invalid expiry time - const BLOCK_ALREADY_BLOCKED = 6; // User is already blocked /** * Backend block code. * $userID and $expiry will be filled accordingly - * Returns one of the BLOCK_* constants + * @return array(message key, arguments) on failure, empty array on success */ function doBlock(&$userId = null, &$expiry = null) { @@ -313,23 +306,23 @@ # IPv4 if ( $wgSysopRangeBans ) { if ( !IP::isIPv4( $this->BlockAddress ) || $matches[2] < 16 || $matches[2] > 32 ) { - return self::BLOCK_RANGE_INVALID; + return array('ip_range_invalid'); } $this->BlockAddress = Block::normaliseRange( $this->BlockAddress ); } else { # Range block illegal - return self::BLOCK_RANGE_DISABLED; + return array('range_block_disabled'); } } else if ( preg_match( "/^($rxIP6)\\/(\\d{1,3})$/", $this->BlockAddress, $matches ) ) { # IPv6 if ( $wgSysopRangeBans ) { if ( !IP::isIPv6( $this->BlockAddress ) || $matches[2] < 64 || $matches[2] > 128 ) { - return self::BLOCK_RANGE_INVALID; + return array('ip_range_invalid'); } $this->BlockAddress = Block::normaliseRange( $this->BlockAddress ); } else { # Range block illegal - return self::BLOCK_RANGE_DISABLED; + return array('range_block_disabled'); } } else { # Username block @@ -337,13 +330,12 @@ $user = User::newFromName( $this->BlockAddress ); if( !is_null( $user ) && $user->getID() ) { # Use canonical name - $this->BlockAddress = $user->getName(); $userId = $user->getID(); } else { - return self::BLOCK_NONEXISTENT_USER; + return array('nosuchusershort', htmlspecialchars($user->getName())); } } else { - return self::BLOCK_IP_INVALID; + return array('badipaddress'); } } } @@ -361,7 +353,7 @@ $expirestr = $this->BlockOther; if (strlen($expirestr) == 0) { - return self::BLOCK_EXPIRY_INVALID; + return array('ipb_expiry_invalid'); } if ( $expirestr == 'infinite' || $expirestr == 'indefinite' ) { @@ -371,7 +363,7 @@ $expiry = strtotime( $expirestr ); if ( $expiry < 0 || $expiry === false ) { - return self::BLOCK_EXPIRY_INVALID; + return array('ipb_expiry_invalid'); } $expiry = wfTimestamp( TS_MW, $expiry ); @@ -387,7 +379,7 @@ if (wfRunHooks('BlockIp', array(&$block, &$wgUser))) { if ( !$block->insert() ) { - return self::BLOCK_ALREADY_BLOCKED; + return array('ipb_already_blocked', htmlspecialchars($this->BlockAddress)); } wfRunHooks('BlockIpComplete', array($block, $wgUser)); @@ -404,8 +396,10 @@ $reasonstr, $logParams ); # Report to the user - return self::BLOCK_SUCCESS; + return array(); } + else + return array('hookaborted'); } /** @@ -416,34 +410,14 @@ { global $wgOut; $retval = $this->doBlock(); - switch($retval) - { - case self::BLOCK_RANGE_INVALID: - $this->showForm( wfMsg( 'ip_range_invalid' ) ); - return; - case self::BLOCK_RANGE_DISABLED: - $this->showForm( wfMsg( 'range_block_disabled' ) ); - return; - case self::BLOCK_NONEXISTENT_USER: - $this->showForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->BlockAddress ) ) ); - return; - case self::BLOCK_IP_INVALID: - $this->showForm( wfMsg( 'badipaddress' ) ); - return; - case self::BLOCK_EXPIRY_INVALID: - $this->showForm( wfMsg( 'ipb_expiry_invalid' ) ); - return; - case self::BLOCK_ALREADY_BLOCKED: - $this->showForm( wfMsg( 'ipb_already_blocked', htmlspecialchars( $this->BlockAddress ) ) ); - return; - case self::BLOCK_SUCCESS: - $titleObj = SpecialPage::getTitleFor( 'Blockip' ); - $wgOut->redirect( $titleObj->getFullURL( 'action=success&ip=' . - urlencode( $this->BlockAddress ) ) ); - return; - default: - throw new MWException( __METHOD__ . ": Unknown return value ``{$retval}''" ); + if(empty($retval)) { + $titleObj = SpecialPage::getTitleFor( 'Blockip' ); + $wgOut->redirect( $titleObj->getFullURL( 'action=success&ip=' . + urlencode( $this->BlockAddress ) ) ); + return; } + $key = array_shift($retval); + $this->showForm(wfMsgReal($key, $retval)); } function showSuccess() { Modified: branches/ApiEdit_Vodafone/includes/SpecialExport.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialExport.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialExport.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -50,6 +50,61 @@ } /** + * Expand a list of pages to include templates used in those pages. + * @param $inputPages array, list of titles to look up + * @param $pageSet array, associative array indexed by titles for output + * @return array associative array index by titles + */ +function wfExportGetTemplates( $inputPages, $pageSet ) { + return wfExportGetLinks( $inputPages, $pageSet, + 'templatelinks', + array( 'tl_namespace AS namespace', 'tl_title AS title' ), + array( 'page_id=tl_from' ) ); +} + +/** + * Expand a list of pages to include images used in those pages. + * @param $inputPages array, list of titles to look up + * @param $pageSet array, associative array indexed by titles for output + * @return array associative array index by titles + */ +function wfExportGetImages( $inputPages, $pageSet ) { + return wfExportGetLinks( $inputPages, $pageSet, + 'imagelinks', + array( NS_IMAGE . ' AS namespace', 'il_to AS title' ), + array( 'page_id=il_from' ) ); +} + +/** + * Expand a list of pages to include items used in those pages. + * @private + */ +function wfExportGetLinks( $inputPages, $pageSet, $table, $fields, $join ) { + $dbr = wfGetDB( DB_SLAVE ); + foreach( $inputPages as $page ) { + $title = Title::newFromText( $page ); + $pageSet[$title->getPrefixedText()] = true; + if( $title ) { + /// @fixme May or may not be more efficient to batch these + /// by namespace when given multiple input pages. + $result = $dbr->select( + array( 'page', $table ), + $fields, + array_merge( $join, + array( + 'page_namespace' => $title->getNamespace(), + 'page_title' => $title->getDbKey() ) ), + __METHOD__ ); + foreach( $result as $row ) { + $template = Title::makeTitle( $row->namespace, $row->title ); + $pageSet[$template->getPrefixedText()] = true; + } + } + } + return $pageSet; +} + +/** * */ function wfSpecialExport( $page = '' ) { @@ -66,6 +121,11 @@ if ( $catname !== '' && $catname !== NULL && $catname !== false ) { $t = Title::makeTitleSafe( NS_CATEGORY, $catname ); if ( $t ) { + /** + * @fixme This can lead to hitting memory limit for very large + * categories. Ideally we would do the lookup synchronously + * during the export in a single query. + */ $catpages = wfExportGetPagesFromCategory( $t ); if ( $catpages ) $page .= "\n" . implode( "\n", $catpages ); } @@ -123,7 +183,7 @@ $list_authors = $wgRequest->getCheck( 'listauthors' ); if ( !$curonly || !$wgExportAllowListContributors ) $list_authors = false ; - + if ( $doexport ) { $wgOut->disable(); @@ -136,8 +196,26 @@ $filename = urlencode( $wgSitename . '-' . wfTimestampNow() . '.xml' ); $wgRequest->response()->header( "Content-disposition: attachment;filename={$filename}" ); } - $pages = explode( "\n", $page ); + + /* Split up the input and look up linked pages */ + $inputPages = array_filter( explode( "\n", $page ) ); + $pageSet = array_flip( $inputPages ); + if( $wgRequest->getCheck( 'templates' ) ) { + $pageSet = wfExportGetTemplates( $inputPages, $pageSet ); + } + + /* + // Enable this when we can do something useful exporting/importing image information. :) + if( $wgRequest->getCheck( 'images' ) ) { + $pageSet = wfExportGetImages( $inputPages, $pageSet ); + } + */ + + $pages = array_keys( $pageSet ); + + /* Ok, let's get to it... */ + $db = wfGetDB( DB_SLAVE ); $exporter = new WikiExporter( $db, $history ); $exporter->list_authors = $list_authors ; @@ -188,6 +266,9 @@ } else { $wgOut->addHtml( wfMsgExt( 'exportnohistory', 'parse' ) ); } + $form .= Xml::checkLabel( wfMsg( 'export-templates' ), 'templates', 'wpExportTemplates', false ) . '<br />'; + // Enable this when we can do something useful exporting/importing image information. :) + //$form .= Xml::checkLabel( wfMsg( 'export-images' ), 'images', 'wpExportImages', false ) . '<br />'; $form .= Xml::checkLabel( wfMsg( 'export-download' ), 'wpDownload', 'wpDownload', true ) . '<br />'; $form .= Xml::submitButton( wfMsg( 'export-submit' ) ); Modified: branches/ApiEdit_Vodafone/includes/SpecialIpblocklist.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialIpblocklist.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialIpblocklist.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -150,7 +150,7 @@ * Backend code for unblocking. doSubmit() wraps around this. * $range is only used when UNBLOCK_BLOCKED_AS_RANGE is returned, in which * case it contains the range $ip is part of. - * Returns one of UNBLOCK_* + * @return array array(message key, parameters) on failure, empty array on success */ static function doUnblock(&$id, &$ip, &$reason, &$range = null) @@ -158,7 +158,7 @@ if ( $id ) { $block = Block::newFromID( $id ); if ( !$block ) { - return self::UNBLOCK_NO_SUCH_ID; + return array('ipb_cant_unblock', htmlspecialchars($id)); } $ip = $block->getRedactedName(); } else { @@ -168,19 +168,20 @@ $id = substr( $ip, 1 ); $block = Block::newFromID( $id ); if( !$block ) { - return self::UNBLOCK_NO_SUCH_ID; + return array('ipb_cant_unblock', htmlspecialchars($id)); } + $ip = $block->getRedactedName(); } else { $block = Block::newFromDB( $ip ); if ( !$block ) { - return self::UNBLOCK_USER_NOT_BLOCKED; + return array('ipb_cant_unblock', htmlspecialchars($id)); } if( $block->mRangeStart != $block->mRangeEnd && !strstr( $ip, "/" ) ) { /* If the specified IP is a single address, and the block is * a range block, don't unblock the range. */ $range = $block->mAddress; - return self::UNBLOCK_BLOCKED_AS_RANGE; + return array('ipb_blocked_as_range', $ip, $range); } } } @@ -189,31 +190,28 @@ # Delete block if ( !$block->delete() ) { - return self::UNBLOCK_UNKNOWNERR; + return array('ipb_cant_unblock', htmlspecialchars($id)); } # Make log entry $log = new LogPage( 'block' ); $log->addEntry( 'unblock', Title::makeTitle( NS_USER, $ip ), $reason ); - return self::UNBLOCK_SUCCESS; + return array(); } function doSubmit() { global $wgOut; - $retval = self::doUnblock(&$this->id, &$this->ip, &$this->reason, &$range); - if($retval == self::UNBLOCK_SUCCESS) { - # Report to the user - $titleObj = SpecialPage::getTitleFor( "Ipblocklist" ); - $success = $titleObj->getFullURL( "action=success&successip=" . urlencode( $this->ip ) ); - $wgOut->redirect( $success ); - } else if($retval == self::UNBLOCK_BLOCKED_AS_RANGE) { - $this->showForm( wfMsg( 'ipb_blocked_as_range', $this->ip, $range ) ); - } else { // UI code doesn't distinguish between errors much. Maybe it should - if ( !$this->ip && $this->id ) { - $this->ip = '#' . $this->id; - } - $this->showForm( wfMsg( 'ipb_cant_unblock', htmlspecialchars( $this->id ) ) ); + $retval = self::doUnblock($this->id, $this->ip, $this->reason, $range); + if(!empty($retval)) + { + $key = array_shift($retval); + $this->showForm(wfMsgReal($key, $retval)); + return; } + # Report to the user + $titleObj = SpecialPage::getTitleFor( "Ipblocklist" ); + $success = $titleObj->getFullURL( "action=success&successip=" . urlencode( $this->ip ) ); + $wgOut->redirect( $success ); } function showList( $msg ) { Modified: branches/ApiEdit_Vodafone/includes/SpecialUndelete.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialUndelete.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialUndelete.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -303,9 +303,6 @@ return ($n > 0); } - const UNDELETE_NOTHINGRESTORED = 0; // No revisions could be restored - const UNDELETE_NOTAVAIL = -1; // Not all requested revisions are available - const UNDELETE_UNKNOWNERR = -2; // Unknown error /** * Restore the given (or all) text and file revisions for the page. * Once restored, the items will be removed from the archive tables. @@ -315,7 +312,8 @@ * @param string $comment * @param array $fileVersions * - * @return array(number of revisions restored, number of file versions restored, log reason) on success or UNDELETE_* on failure + * @return array(number of file revisions restored, number of image revisions restored, log message) + * on success, false on failure */ function undelete( $timestamps, $comment = '', $fileVersions = array() ) { // If both the set of text revisions and file revisions are empty, @@ -335,8 +333,8 @@ if( $restoreText ) { $textRestored = $this->undeleteRevisions( $timestamps ); - if($textRestored < 0) // It must be one of UNDELETE_* - return $textRestored; + if($textRestored === false) // It must be one of UNDELETE_* + return false; } else { $textRestored = 0; } @@ -357,7 +355,7 @@ $wgContLang->formatNum( $filesRestored ) ); } else { wfDebug( "Undelete: nothing undeleted...\n" ); - return self::UNDELETE_NOTHINGRESTORED; + return false; } if( trim( $comment ) != '' ) @@ -376,10 +374,11 @@ * @param string $comment * @param array $fileVersions * - * @return int number of revisions restored on success or UNDELETE_* on failure + * @return mixed number of revisions restored or false on failure */ private function undeleteRevisions( $timestamps ) { - if ( wfReadOnly() ) return 0; + if ( wfReadOnly() ) + return false; $restoreAll = empty( $timestamps ); @@ -444,7 +443,7 @@ ); if( $dbw->numRows( $result ) < count( $timestamps ) ) { wfDebug( __METHOD__.": couldn't find all requested rows\n" ); - return self::UNDELETE_NOTAVAIL; + return false; } $revision = null; Modified: branches/ApiEdit_Vodafone/includes/SpecialVersion.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialVersion.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialVersion.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -102,7 +102,7 @@ wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) ); $out = "<h2>Extensions</h2>\n"; - $out .= wfOpenElement('table', array('id' => 'sv-ext') ); + $out .= Xml::openElement('table', array('id' => 'sv-ext') ); foreach ( $extensionTypes as $type => $text ) { if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) { @@ -143,7 +143,7 @@ $out .= $this->openExtType('Skin extension functions'); $out .= '<tr><td colspan="3">' . $this->listToText( $wgSkinExtensionFunction ) . "</td></tr>\n"; } - $out .= wfCloseElement( 'table' ); + $out .= Xml::closeElement( 'table' ); return $out; } @@ -187,7 +187,7 @@ ksort( $myWgHooks ); $ret = "<h2>Hooks</h2>\n" - . wfOpenElement('table', array('id' => 'sv-hooks') ) + . Xml::openElement('table', array('id' => 'sv-hooks') ) . "<tr><th>Hook name</th><th>Subscribed by</th></tr>\n"; foreach ($myWgHooks as $hook => $hooks) @@ -205,13 +205,13 @@ if(!$this->firstExtOpened) { // Insert a spacing line - $out .= '<tr class="sv-space">' . wfElement( 'td', $opt ) . "</tr>\n"; + $out .= '<tr class="sv-space">' . Xml::element( 'td', $opt ) . "</tr>\n"; } $this->firstExtOpened = false; if($name) { $opt['id'] = "sv-$name"; } - $out .= "<tr>" . wfElement( 'th', $opt, $text) . "</tr>\n"; + $out .= "<tr>" . Xml::element( 'th', $opt, $text) . "</tr>\n"; return $out; } Modified: branches/ApiEdit_Vodafone/includes/SpecialWithoutinterwiki.php =================================================================== --- branches/ApiEdit_Vodafone/includes/SpecialWithoutinterwiki.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/SpecialWithoutinterwiki.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -8,13 +8,41 @@ * @author Rob Church <robchur[at]gmail.com> */ class WithoutInterwikiPage extends PageQueryPage { + private $prefix = ''; function getName() { return 'Withoutinterwiki'; } function getPageHeader() { - return '<p>' . wfMsgExt( 'withoutinterwiki-header', array( 'parseinline' ) ) . '</p>'; + global $wgScript, $wgContLang; + $prefix = $this->prefix; + $t = SpecialPage::getTitleFor( $this->getName() ); + $align = $wgContLang->isRtl() ? 'left' : 'right'; + + $s = '<p>' . wfMsgExt( 'withoutinterwiki-header', array( 'parseinline' ) ) . '</p>'; + $s .= Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) ); + $s .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ); + $s .= Xml::hidden( 'title', $t->getPrefixedText() ); + $s .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'withoutinterwiki' ) ); + $s .= "<tr> + <td align='$align'>" . + Xml::label( wfMsg( 'allpagesprefix' ), 'wiprefix' ) . + "</td> + <td>" . + Xml::input( 'prefix', 20, htmlspecialchars ( $prefix ), array( 'id' => 'wiprefix' ) ) . + "</td> + </tr> + <tr> + <td align='$align'></td> + <td>" . + Xml::submitButton( wfMsgHtml( 'withoutinterwiki-submit' ) ) . + "</td> + </tr>"; + $s .= Xml::closeElement( 'table' ); + $s .= Xml::closeElement( 'form' ); + $s .= Xml::closeElement( 'div' ); + return $s; } function sortDescending() { @@ -32,6 +60,7 @@ function getSQL() { $dbr = wfGetDB( DB_SLAVE ); list( $page, $langlinks ) = $dbr->tableNamesN( 'page', 'langlinks' ); + $prefix = $this->prefix ? "AND page_title LIKE '" . $dbr->escapeLike( $this->prefix ) . "%'" : ''; return "SELECT 'Withoutinterwiki' AS type, page_namespace AS namespace, @@ -42,14 +71,22 @@ ON ll_from = page_id WHERE ll_title IS NULL AND page_namespace=" . NS_MAIN . " - AND page_is_redirect = 0"; + AND page_is_redirect = 0 + {$prefix}"; } + function setPrefix( $prefix = '' ) { + $this->prefix = $prefix; + } + } function wfSpecialWithoutinterwiki() { + global $wgRequest; list( $limit, $offset ) = wfCheckLimits(); + $prefix = $wgRequest->getVal( 'prefix' ); $wip = new WithoutInterwikiPage(); + $wip->setPrefix( $prefix ); $wip->doQuery( $offset, $limit ); } Modified: branches/ApiEdit_Vodafone/includes/Title.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Title.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Title.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -207,6 +207,9 @@ * Make an array of titles from an array of IDs */ public static function newFromIDs( $ids ) { + if ( !count( $ids ) ) { + return array(); + } $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'page', array( 'page_namespace', 'page_title' ), 'page_id IN (' . $dbr->makeList( $ids ) . ')', __METHOD__ ); @@ -2305,10 +2308,14 @@ return 'badarticleerror'; } - if ( $auth && ( - !$this->userCan( 'edit' ) || !$nt->userCan( 'edit' ) || - !$this->userCan( 'move' ) || !$nt->userCan( 'move' ) ) ) { - return 'protectedpage'; + if ( $auth ) { + global $wgUser; + $errors = array_merge($this->getUserPermissionsErrors('move', $wgUser), + $this->getUserPermissionsErrors('edit', $wgUser), + $nt->getUserPermissionsErrors('move', $wgUser), + $nt->getUserPermissionsErrors('edit', $wgUser)); + if($errors !== array()) + return $errors[0][0]; } global $wgUser; Modified: branches/ApiEdit_Vodafone/includes/Wiki.php =================================================================== --- branches/ApiEdit_Vodafone/includes/Wiki.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/Wiki.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -220,6 +220,10 @@ switch( $title->getNamespace() ) { case NS_IMAGE: + $file = wfFindFile( $title ); + if( $file && $file->getRedirected() ) { + return new Article( $title ); + } return new ImagePage( $title ); case NS_CATEGORY: return new CategoryPage( $title ); @@ -245,7 +249,8 @@ // Namespace might change when using redirects if( ( $action == 'view' || $action == 'render' ) && !$request->getVal( 'oldid' ) && - $request->getVal( 'redirect' ) != 'no' ) { + $request->getVal( 'redirect' ) != 'no' && + !( $wgTitle->getNamespace() == NS_IMAGE && wfFindFile( $wgTitle->getText() ) ) ) { $dbr = wfGetDB(DB_SLAVE); $article->loadPageData($article->pageDataFromTitle($dbr, $title)); Modified: branches/ApiEdit_Vodafone/includes/api/ApiBase.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiBase.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiBase.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -554,6 +554,10 @@ * Array that maps message keys to error messages. $1 and friends are replaced. */ public static $messageMap = array( + // This one MUST be present, or dieUsageMsg() will recurse infinitely + 'unknownerror' => array('code' => 'unknownerror', 'info' => "Unknown error: ``\$1''"), + + // Messages from Title::getUserPermissionsErrors() 'ns-specialprotected' => array('code' => 'unsupportednamespace', 'info' => "Pages in the Special namespace can't be edited"), 'protectedinterface' => array('code' => 'protectednamespace-interface', 'info' => "You're not allowed to edit interface messages"), 'namespaceprotected' => array('code' => 'protectednamespace', 'info' => "You're not allowed to edit pages in the ``\$1'' namespace"), @@ -565,12 +569,55 @@ 'badaccess-group1' => array('code' => 'permissiondenied', 'info' => "Permission denied"), // Can't use the parameter 'cause it's wikilinked 'badaccess-group2' => array('code' => 'permissiondenied', 'info' => "Permission denied"), 'badaccess-groups' => array('code' => 'permissiondenied', 'info' => "Permission denied"), - 'unknownerror' => array('code' => 'unknownerror', 'info' => "Unknown error"), 'titleprotected' => array('code' => 'protectedtitle', 'info' => "This title has been protected from creation"), 'nocreate-loggedin' => array('code' => 'cantcreate', 'info' => "You don't have permission to create new pages"), 'nocreatetext' => array('code' => 'cantcreate-anon', 'info' => "Anonymous users can't create new pages"), 'movenologintext' => array('code' => 'cantmove-anon', 'info' => "Anonymous users can't move pages"), - 'movenotallowed' => array('code' => 'cantmove', 'info' => "You don't have permission to move pages") + 'movenotallowed' => array('code' => 'cantmove', 'info' => "You don't have permission to move pages"), + 'confirmedittiext' => array('code' => 'confirmemail', 'info' => "You must confirm your e-mail address before you can edit"), + 'blockedtext' => array('code' => 'blocked', 'info' => "You have been blocked from editing"), + 'autoblockedtext' => array('code' => 'autoblocked', 'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"), + + // Miscellaneous interface messages + 'alreadyrolled' => array('code' => 'alreadyrolled', 'info' => "The page you tried to rollback was already rolled back"), + 'cantrollback' => array('code' => 'onlyauthor', 'info' => "The page you tried to rollback only has one author"), + 'readonlytext' => array('code' => 'readonly', 'info' => "The wiki is currently in read-only mode"), + 'sessionfailure' => array('code' => 'badtoken', 'info' => "Invalid token"), + 'cannotdelete' => array('code' => 'cantdelete', 'info' => "Couldn't delete ``\$1''. Maybe it was deleted already by someone else"), + 'notanarticle' => array('code' => 'missingtitle', 'info' => "The page you requested doesn't exist"), + 'selfmove' => array('code' => 'selfmove', 'info' => "Can't move a page to itself"), + 'immobile_namespace' => array('code' => 'immobilenamespace', 'info' => "You tried to move pages from or to a namespace that is protected from moving"), + 'articleexists' => array('code' => 'articleexists', 'info' => "The destination article already exists and is not a redirect to the source article"), + 'protectedpage' => array('code' => 'protectedpage', 'info' => "You don't have permission to perform this move"), + 'hookaborted' => array('code' => 'hookaborted', 'info' => "The modification you tried to make was aborted by an extension hook"), + 'cantmove-titleprotected' => array('code' => 'protectedtitle', 'info' => "The destination article has been protected from creation"), + // 'badarticleerror' => shouldn't happen + // 'badtitletext' => shouldn't happen + 'ip_range_invalid' => array('code' => 'invalidrange', 'info' => "Invalid IP range"), + 'range_block_disabled' => array('code' => 'rangedisabled', 'info' => "Blocking IP ranges has been disabled"), + 'nosuchusershort' => array('code' => 'nosuchuser', 'info' => "The user you specified doesn't exist"), + 'badipaddress' => array('code' => 'invalidip', 'info' => "Invalid IP address specified"), + 'ipb_expiry_invalid' => array('code' => 'invalidexpiry', 'info' => "Invalid expiry time"), + 'ipb_already_blocked' => array('code' => 'alreadyblocked', 'info' => "The user you tried to block was already blocked"), + 'ipb_blocked_as_range' => array('code' => 'blockedasrange', 'info' => "IP address ``\$1'' was blocked as part of range ``\$2''. You can't unblock the IP invidually, but you can unblock the range as a whole."), + 'ipb_cant_unblock' => array('code' => 'cantunblock', 'info' => "The block you specified was not found. It may have been unblocked already"), + + // API-specific messages + 'missingparam' => array('code' => 'no$1', 'info' => "The \$1 parameter must be set"), + 'invalidtitle' => array('code' => 'invalidtitle', 'info' => "Bad title ``\$1''"), + 'invaliduser' => array('code' => 'invaliduser', 'info' => "Invalid username ``\$1''"), + 'invalidexpiry' => array('code' => 'invalidexpiry', 'info' => "Invalid expiry time"), + 'pastexpiry' => array('code' => 'pastexpiry', 'info' => "Expiry time is in the past"), + 'create-titleexists' => array('code' => 'create-titleexists', 'info' => "Existing titles can't be protected with 'create'"), + 'missingtitle-createonly' => array('code' => 'missingtitle-createonly', 'info' => "Missing titles can only be protected with 'create'"), + 'cantblock' => array('code' => 'cantblock', 'info' => "You don't have permission to block users"), + 'canthide' => array('code' => 'canthide', 'info' => "You don't have permission to hide user names from the block log"), + 'cantblock-email' => array('code' => 'cantblock-email', 'info' => "You don't have permission to block users from sending e-mail through the wiki"), + 'unblock-notarget' => array('code' => 'notarget', 'info' => "Either the id or the user parameter must be set"), + 'unblock-idanduser' => array('code' => 'idanduser', 'info' => "The id and user parameters can\'t be used together"), + 'cantunblock' => array('code' => 'permissiondenied', 'info' => "You don't have permission to unblock users"), + 'cannotundelete' => array('code' => 'cantundelete', 'info' => "Couldn't undelete: the requested revisions may not exist, or may have been undeleted already"), + 'permdenied-undelete' => array('code' => 'permissiondenied', 'info' => "You don't have permission to restore deleted revisions"), ); /** @@ -580,9 +627,9 @@ public function dieUsageMsg($error) { $key = array_shift($error); if(isset(self::$messageMap[$key])) - $this->dieUsage(wfMsgReplaceArgs(self::$messageMap[$key]['info'], $error), self::$messageMap[$key]['code']); - // If the key isn't present, throw an "unknown error - $this->dieUsage(self::$messageMap['unknownerror']['info'], self::$messageMap['unknownerror']['code']); + $this->dieUsage(wfMsgReplaceArgs(self::$messageMap[$key]['info'], $error), wfMsgReplaceArgs(self::$messageMap[$key]['code'], $error)); + // If the key isn't present, throw an "unknown error" + $this->dieUsageMsg(array('unknownerror', $key)); } /** @@ -605,6 +652,13 @@ public function isEditMode() { return false; } + + /** + * Indicates whether this module must be called with a POST request + */ + public function mustBePosted() { + return false; + } /** Modified: branches/ApiEdit_Vodafone/includes/api/ApiBlock.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiBlock.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiBlock.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -61,21 +61,23 @@ } if(is_null($params['user'])) - $this->dieUsage('The user parameter must be set', 'nouser'); + $this->dieUsageMsg(array('missingparam', 'user')); if(is_null($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); + $this->dieUsageMsg(array('sessionfailure')); if(!$wgUser->isAllowed('block')) - $this->dieUsage('You don\'t have permission to block users', 'permissiondenied'); + $this->dieUsageMsg(array('cantblock')); if($params['hidename'] && !$wgUser->isAllowed('hideuser')) - $this->dieUsage('You don\'t have permission to hide user names from the block log', 'nohide'); + $this->dieUsageMsg(array('canthide')); + if($params['noemail'] && !$wgUser->isAllowed('blockemail')) + $this->dieUsageMsg(array('cantblock-email')); if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); + $this->dieUsageMsg(array('readonlytext')); $form = new IPBlockForm(''); $form->BlockAddress = $params['user']; - $form->BlockReason = $params['reason']; + $form->BlockReason = (is_null($params['reason']) ? '' : $params['reason']); $form->BlockReasonList = 'other'; $form->BlockExpiry = ($params['expiry'] == 'never' ? 'infinite' : $params['expiry']); $form->BlockOther = ''; @@ -88,27 +90,11 @@ $dbw = wfGetDb(DB_MASTER); $dbw->begin(); $retval = $form->doBlock($userID, $expiry); - switch($retval) - { - case IPBlockForm::BLOCK_SUCCESS: - break; // We'll deal with that later - case IPBlockForm::BLOCK_RANGE_INVALID: - $this->dieUsage("Invalid IP range ``{$params['user']}''", 'invalidrange'); - case IPBlockForm::BLOCK_RANGE_DISABLED: - $this->dieUsage('Blocking IP ranges has been disabled', 'rangedisabled'); - case IPBlockForm::BLOCK_NONEXISTENT_USER: - $this->dieUsage("User ``{$params['user']}'' doesn't exist", 'nosuchuser'); - case IPBlockForm::BLOCK_IP_INVALID: - $this->dieUsage("Invaild IP address ``{$params['user']}''", 'invalidip'); - case IPBlockForm::BLOCK_EXPIRY_INVALID: - $this->dieUsage("Invalid expiry time ``{$params['expiry']}''", 'invalidexpiry'); - case IPBlockForm::BLOCK_ALREADY_BLOCKED: - $this->dieUsage("User ``{$params['user']}'' is already blocked", 'alreadyblocked'); - default: - $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($retval)"); - } + if(!empty($retval)) + // We don't care about multiple errors, just report one of them + $this->dieUsageMsg($retval); + $dbw->commit(); - $res['user'] = $params['user']; $res['userID'] = $userID; $res['expiry'] = ($expiry == Block::infinity() ? 'infinite' : $expiry); @@ -127,6 +113,8 @@ $this->getResult()->addValue(null, $this->getModuleName(), $res); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'user' => null, @@ -152,7 +140,7 @@ 'anononly' => 'Block anonymous users only (i.e. disable anonymous edits for this IP)', 'nocreate' => 'Prevent account creation', 'autoblock' => 'Automatically block the last used IP address, and any subsequent IP addresses they try to login from', - 'noemail' => 'Prevent user from sending e-mail through the wiki', + 'noemail' => 'Prevent user from sending e-mail through the wiki. (Requires the "blockemail" right.)', 'hidename' => 'Hide the username from the block log. (Requires the "hideuser" right.)' ); } Modified: branches/ApiEdit_Vodafone/includes/api/ApiDelete.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiDelete.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiDelete.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -40,14 +40,6 @@ parent :: __construct($main, $action); } - /* Return values for the delete function. */ - const DELETE_SUCCESS = 0; - const DELETE_PERM = 1; - const DELETE_BLOCKED = 2; - const DELETE_READONLY = 3; - const DELETE_BADTOKEN = 4; - const DELETE_BADARTICLE = 5; - /** * Extracts the title, token, and reason from the request parameters and invokes * the local delete() function with these as arguments. It does not make use of @@ -62,49 +54,26 @@ $titleObj = NULL; if(!isset($params['title'])) - $this->dieUsage('The title parameter must be set', 'notitle'); + $this->dieUsageMsg(array('missingparam', 'title')); if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); - // delete() also checks for these, but we wanna save some work - if(!$wgUser->isAllowed('delete')) - $this->dieUsage('You don\'t have permission to delete pages', 'permissiondenied'); - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - $titleObj = Title::newFromText($params['title']); if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + $this->dieUsageMsg(array('invalidtitle', $params['title'])); if(!$titleObj->exists()) - $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); + $this->dieUsageMsg(array('notanarticle')); $articleObj = new Article($titleObj); $reason = (isset($params['reason']) ? $params['reason'] : NULL); $dbw = wfGetDb(DB_MASTER); $dbw->begin(); - $retval = self::delete(&$articleObj, $params['token'], &$reason); + $retval = self::delete($articleObj, $params['token'], $reason); + + if(!empty($retval)) + // We don't care about multiple errors, just report one of them + $this->dieUsageMsg(current($retval)); - switch($retval) - { - case self::DELETE_SUCCESS: - break; // We'll deal with that later - case self::DELETE_PERM: // If we get PERM, BLOCKED or READONLY that's weird, but it's possible - $this->dieUsage('You don\'t have permission to delete', 'permissiondenied'); - case self::DELETE_BLOCKED: - $this->dieUsage('You have been blocked from editing', 'blocked'); - case self::DELETE_READONLY: - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - case self::DELETE_BADTOKEN: - $this->dieUsage('Invalid token', 'badtoken'); - case self::DELETE_BADARTICLE: - $this->dieUsage("The article ``{$params['title']}'' doesn't exist or has already been deleted", 'missingtitle'); - default: - // delete() has apparently invented a new error, which is extremely weird - $this->dieDebug(__METHOD__, "delete() returned an unknown error ($retval)"); - } - // $retval has to be self::DELETE_SUCCESS if we get here $dbw->commit(); $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason); $this->getResult()->addValue(null, $this->getModuleName(), $r); @@ -116,38 +85,41 @@ * @param Article $article - Article object to work on * @param string $token - Delete token (same as edit token) * @param string $reason - Reason for the deletion. Autogenerated if NULL - * @return DELETE_SUCCESS on success, DELETE_* on failure + * @return Title::getUserPermissionsErrors()-like array */ public static function delete(&$article, $token, &$reason = NULL) { global $wgUser; - // Check permissions first - if(!$article->mTitle->userCan('delete')) - return self::DELETE_PERM; - if($wgUser->isBlocked()) - return self::DELETE_BLOCKED; + // Check permissions + $errors = $article->mTitle->getUserPermissionsErrors('delete', $wgUser); + if(!empty($errors)) + return $errors; if(wfReadOnly()) - return self::DELETE_READONLY; + return array(array('readonlytext')); + if($wgUser->isBlocked()) + return array(array('blocked')); // Check token if(!$wgUser->matchEditToken($token)) - return self::DELETE_BADTOKEN; + return array(array('sessionfailure')); // Auto-generate a summary, if necessary if(is_null($reason)) { $reason = $article->generateReason($hasHistory); if($reason === false) - return self::DELETE_BADARTICLE; + return array(array('cannotdelete')); } // Luckily, Article.php provides a reusable delete function that does the hard work for us if($article->doDeleteArticle($reason)) - return self::DELETE_SUCCESS; - return self::DELETE_BADARTICLE; + return array(); + return array(array('cannotdelete', $article->mTitle->getPrefixedText())); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'title' => null, Modified: branches/ApiEdit_Vodafone/includes/api/ApiLogin.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiLogin.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiLogin.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -217,6 +217,8 @@ private function getMemCacheKey() { return wfMemcKey( 'apilogin', 'badlogin', 'ip', wfGetIP() ); } + + public function mustBePosted() { return true; } protected function getAllowedParams() { return array ( Modified: branches/ApiEdit_Vodafone/includes/api/ApiLogout.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiLogout.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiLogout.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -37,7 +37,7 @@ class ApiLogout extends ApiBase { public function __construct($main, $action) { - parent :: __construct($main, $action, 'lo'); + parent :: __construct($main, $action); } public function execute() { Modified: branches/ApiEdit_Vodafone/includes/api/ApiMain.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiMain.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiMain.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -325,8 +325,11 @@ return; } } - + if (!$this->mInternalMode) { + // Ignore mustBePosted() for internal calls + if($module->mustBePosted() && !$this->mRequest->wasPosted()) + $this->dieUsage("The {$this->mAction} module requires a POST request", 'mustbeposted'); // See if custom printer is used $this->mPrinter = $module->getCustomPrinter(); Modified: branches/ApiEdit_Vodafone/includes/api/ApiMove.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiMove.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiMove.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -46,55 +46,45 @@ $titleObj = NULL; if(!isset($params['from'])) - $this->dieUsage('The from parameter must be set', 'nofrom'); + $this->dieUsageMsg(array('missingparam', 'from')); if(!isset($params['to'])) - $this->dieUsage('The to parameter must be set', 'noto'); + $this->dieUsageMsg(array('missingparam', 'to')); if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); + $this->dieUsageMsg(array('sessionfailure')); - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - if($params['noredirect'] && !$wgUser->isAllowed('suppressredirect')) - $this->dieUsage("You don't have permission to suppress redirect creation", 'nosuppress'); - $fromTitle = Title::newFromText($params['from']); if(!$fromTitle) - $this->dieUsage("Bad title ``{$params['from']}''", 'invalidtitle'); + $this->dieUsageMsg(array('invalidtitle', $params['from'])); if(!$fromTitle->exists()) - $this->dieUsage("``{$params['from']}'' doesn't exist", 'missingtitle'); + $this->dieUsageMsg(array('notanarticle')); $fromTalk = $fromTitle->getTalkPage(); - $toTitle = Title::newFromText($params['to']); if(!$toTitle) - $this->dieUsage("Bad title ``{$params['to']}''", 'invalidtitle'); + $this->dieUsageMsg(array('invalidtitle', $params['to'])); $toTalk = $toTitle->getTalkPage(); + // Run getUserPermissionsErrors() here so we get message arguments too, + // rather than just a message key. The latter is troublesome for messages + // that use arguments. + // FIXME: moveTo() should really return an array, requires some + // refactoring of other code, though (mainly SpecialMovepage.php) + $errors = array_merge($fromTitle->getUserPermissionsErrors('move', $wgUser), + $fromTitle->getUserPermissionsErrors('edit', $wgUser), + $toTitle->getUserPermissionsErrors('move', $wgUser), + $toTitle->getUserPermissionsErrors('edit', $wgUser)); + if(!empty($errors)) + // We don't care about multiple errors, just report one of them + $this->dieUsageMsg(current($errors)); + $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $retval = $fromTitle->moveTo($toTitle, true, $params['reason'], !$params['noredirect']); if($retval !== true) - switch($retval) - { - // case 'badtitletext': Can't happen - // case 'badarticleerror': Can't happen - case 'selfmove': - $this->dieUsage("Can't move ``{$params['from']}'' to itself", 'selfmove'); - case 'immobile_namespace': - if($fromTitle->isMovable()) - $this->dieUsage("Pages in the ``{$fromTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-from'); - $this->dieUsage("Pages in the ``{$toTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-to'); - case 'articleexists': - $this->dieUsage("``{$toTitle->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTitle->getPrefixedText()}''", 'targetexists'); - case 'protectedpage': - $this->dieUsage("You don't have permission to move ``{$fromTitle->getPrefixedText()}'' to ``{$toTitle->getPrefixedText()}''", 'permissiondenied'); - default: - throw new MWException( "Title::moveTo: Unknown return value ``{$retval}''" ); - } + $this->dieUsageMsg(array($retval)); + $r = array('from' => $fromTitle->getPrefixedText(), 'to' => $toTitle->getPrefixedText(), 'reason' => $params['reason']); if(!$params['noredirect']) $r['redirectcreated'] = ''; @@ -111,36 +101,17 @@ } // We're not gonna dieUsage() on failure, since we already changed something else - switch($retval) - { - case 'immobile_namespace': - if($fromTalk->isMovable()) - { - $r['talkmove-error-code'] = 'immobilenamespace-from'; - $r['talkmove-error-info'] = "Pages in the ``{$fromTalk->getNsText()}'' namespace can't be moved"; - } - else - { - $r['talkmove-error-code'] = 'immobilenamespace-to'; - $r['talkmove-error-info'] = "Pages in the ``{$toTalk->getNsText()}'' namespace can't be moved"; - } - break; - case 'articleexists': - $r['talkmove-error-code'] = 'targetexists'; - $r['talkmove-error-info'] = "``{$toTalk->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTalk->getPrefixedText()}''"; - break; - case 'protectedpage': - $r['talkmove-error-code'] = 'permissiondenied'; - $r['talkmove-error-info'] = "You don't have permission to move ``{$fromTalk->getPrefixedText()}'' to ``{$toTalk->getPrefixedText()}''"; - default: - $r['talkmove-error-code'] = 'unknownerror'; - $r['talkmove-error-info'] = "Unknown error ``$retval''"; - } + { + $r['talkmove-error-code'] = ApiBase::$messageMap[$retval]['code']; + $r['talkmove-error-info'] = ApiBase::$messageMap[$retval]['info']; + } } $dbw->commit(); // Make sure all changes are really written to the DB $this->getResult()->addValue(null, $this->getModuleName(), $r); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'from' => null, Modified: branches/ApiEdit_Vodafone/includes/api/ApiProtect.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiProtect.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiProtect.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -43,24 +43,23 @@ $titleObj = NULL; if(!isset($params['title'])) - $this->dieUsage('The title parameter must be set', 'notitle'); + $this->dieUsageMsg(array('missingparam', 'title')); if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); if(!isset($params['protections']) || empty($params['protections'])) - $this->dieUsage('The protections parameter must be set', 'noprotections'); + $this->dieUsageMsg(array('missingparam', 'protections')); - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); + $this->dieUsageMsg(array('sessionfailure')); $titleObj = Title::newFromText($params['title']); if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); - if(!$titleObj->userCan('protect')) - $this->dieUsage('You don\'t have permission to change protection levels', 'permissiondenied'); + $this->dieUsageMsg(array('invalidtitle', $params['title'])); + + $errors = $titleObj->getUserPermissionsErrors('protect', $wgUser); + if(!empty($errors)) + // We don't care about multiple errors, just report one of them + $this->dieUsageMsg(current($errors)); if(in_array($params['expiry'], array('infinite', 'indefinite', 'never'))) $expiry = Block::infinity(); @@ -68,11 +67,11 @@ { $expiry = strtotime($params['expiry']); if($expiry < 0 || $expiry == false) - $this->dieUsage('Invalid expiry time', 'invalidexpiry'); + $this->dieUsageMsg(array('invalidexpiry')); $expiry = wfTimestamp(TS_MW, $expiry); if($expiry < wfTimestampNow()) - $this->dieUsage('Expiry time is in the past', 'pastexpiry'); + $this->dieUsageMsg(array('pastexpiry')); } $protections = array(); @@ -81,9 +80,9 @@ $p = explode('=', $prot); $protections[$p[0]] = ($p[1] == 'all' ? '' : $p[1]); if($titleObj->exists() && $p[0] == 'create') - $this->dieUsage("Existing titles can't be protected with 'create'", 'create-titleexists'); + $this->dieUsageMsg(array('create-titleexists')); if(!$titleObj->exists() && $p[0] != 'create') - $this->dieUsage("Missing titles can only be protected with 'create'", 'missingtitle'); + $this->dieUsageMsg(array('missingtitles-createonly')); } $dbw = wfGetDb(DB_MASTER); @@ -95,15 +94,23 @@ $ok = $titleObj->updateTitleProtection($protections['create'], $params['reason'], $expiry); if(!$ok) // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? - $this->dieUsage('Unknown error', 'unknownerror'); + // Just throw an unknown error in this case, as it's very likely to be a race condition + $this->dieUsageMsg(array()); $dbw->commit(); - $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason'], 'expiry' => wfTimestamp(TS_ISO_8601, $expiry)); + $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason']); + if($expiry == Block::infinity()) + $res['expiry'] = 'infinity'; + else + $res['expiry'] = wfTimestamp(TS_ISO_8601, $expiry); + if($params['cascade']) $res['cascade'] = ''; $res['protections'] = $protections; $this->getResult()->addValue(null, $this->getModuleName(), $res); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'title' => null, Modified: branches/ApiEdit_Vodafone/includes/api/ApiQueryAllmessages.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiQueryAllmessages.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiQueryAllmessages.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -42,6 +42,13 @@ public function execute() { global $wgMessageCache; $params = $this->extractRequestParams(); + + if(!is_null($params['lang'])) + { + global $wgLang; + $wgLang = Language::factory($params['lang']); + } + //Determine which messages should we print $messages_target = array(); @@ -93,6 +100,7 @@ ApiBase :: PARAM_DFLT => '*', ), 'filter' => array(), + 'lang' => null, ); } @@ -100,6 +108,7 @@ return array ( 'messages' => 'Which messages to output. "*" means all messages', 'filter' => 'Return only messages that contains specified string', + 'lang' => 'Language code', ); } @@ -110,7 +119,7 @@ protected function getExamples() { return array( 'api.php?action=query&meta=allmessages&amfilter=ipb-', - 'api.php?action=query&meta=allmessages&ammessages=august|mainpage', + 'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de', ); } Modified: branches/ApiEdit_Vodafone/includes/api/ApiQueryAllpages.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiQueryAllpages.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiQueryAllpages.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -95,10 +95,22 @@ $this->dieUsage('prlevel may not be used without prtype', 'params'); } - $this->addTables('page'); + if($params['filterlanglinks'] == 'withoutlanglinks') { + $pageName = $this->getDB()->tableName('page'); + $llName = $this->getDB()->tableName('langlinks'); + $tables = "$pageName LEFT JOIN $llName ON page_id=ll_from"; + $this->addWhere('ll_from IS NULL'); + $this->addTables($tables); + $forceNameTitleIndex = false; + } else if($params['filterlanglinks'] == 'withlanglinks') { + $this->addTables(array('page', 'langlinks')); + $this->addWhere('page_id=ll_from'); + $forceNameTitleIndex = false; + } else { + $this->addTables('page'); + } if ($forceNameTitleIndex) $this->addOption('USE INDEX', 'name_title'); - if (is_null($resultPageSet)) { $this->addFields(array ( @@ -191,6 +203,14 @@ 'ascending', 'descending' ) + ), + 'filterlanglinks' => array( + ApiBase :: PARAM_TYPE => array( + 'withlanglinks', + 'withoutlanglinks', + 'all' + ), + ApiBase :: PARAM_DFLT => 'all' ) ); } @@ -206,6 +226,7 @@ 'maxsize' => 'Limit to pages with at most this many bytes', 'prtype' => 'Limit to protected pages only', 'prlevel' => 'The protection level (must be used with apprtype= parameter)', + 'filterlanglinks' => 'Filter based on whether a page has langlinks', 'limit' => 'How many total pages to return.' ); } Modified: branches/ApiEdit_Vodafone/includes/api/ApiQueryImageInfo.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiQueryImageInfo.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiQueryImageInfo.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -42,16 +42,20 @@ public function execute() { $params = $this->extractRequestParams(); - $history = $params['history']; - $prop = array_flip($params['prop']); - $fld_timestamp = isset($prop['timestamp']); - $fld_user = isset($prop['user']); - $fld_comment = isset($prop['comment']); - $fld_url = isset($prop['url']); - $fld_size = isset($prop['size']); - $fld_sha1 = isset($prop['sha1']); - $fld_metadata = isset($prop['metadata']); + $this->fld_timestamp = isset($prop['timestamp']); + $this->fld_user = isset($prop['user']); + $this->fld_comment = isset($prop['comment']); + $this->fld_url = isset($prop['url']); + $this->fld_size = isset($prop['size']); + $this->fld_sha1 = isset($prop['sha1']); + $this->fld_metadata = isset($prop['metadata']); + + if($params['urlheight'] != -1 && $params['urlwidth'] == -1) + $this->dieUsage("iiurlheight cannot be used without iiurlwidth", 'iiurlwidth'); + $this->scale = ($params['urlwidth'] != -1); + $this->urlwidth = $params['urlwidth']; + $this->urlheight = $params['urlheight']; $pageIds = $this->getPageSet()->getAllTitlesByNamespace(); if (!empty($pageIds[NS_IMAGE])) { @@ -66,54 +70,21 @@ } else { $repository = $img->getRepoName(); - - $isCur = true; - $count = 0; - while($line = $img->nextHistoryLine()) { // assignment - # FIXME: Limiting to 500 because it's unlimited right now - # 500+ image histories are scarce, but this has DoS potential - # FileRepo.php should be fixed - if($count++ == 500) - break; - $row = get_object_vars( $line ); - $vals = array(); - $prefix = $isCur ? 'img' : 'oi'; - - if ($fld_timestamp) - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row["${prefix}_timestamp"]); - if ($fld_user) { - $vals['user'] = $row["${prefix}_user_text"]; - if(!$row["${prefix}_user"]) - $vals['anon'] = ''; - } - if ($fld_size) { - $vals['size'] = intval($row["{$prefix}_size"]); - $vals['width'] = intval($row["{$prefix}_width"]); - $vals['height'] = intval($row["{$prefix}_height"]); - } - if ($fld_url) - $vals['url'] = $isCur ? $img->getURL() : $img->getArchiveUrl($row["oi_archive_name"]); - if ($fld_comment) - $vals['comment'] = $row["{$prefix}_description"]; - - if ($fld_sha1) - $vals['sha1'] = wfBaseConvert($row["{$prefix}_sha1"], 36, 16, 40); - - if ($fld_metadata) { - $metadata = unserialize($row["{$prefix}_metadata"]); - $vals['metadata'] = $metadata ? $metadata : null; - $this->getResult()->setIndexedTagName_recursive($vals['metadata'], 'meta'); - } - - $data[] = $vals; - - if (!$history) // Stop after the first line. - break; - - $isCur = false; + + // Get information about the current version first + // Check that the current version is within the start-end boundaries + if((is_null($params['start']) || $img->getTimestamp() <= $params['start']) && + (is_null($params['end']) || $img->getTimestamp() >= $params['end'])) { + $data[] = $this->getInfo($img); } - $img->resetHistory(); + // Now get the old revisions + if($params['limit'] > 1) { + $oldies = $img->getHistory($params['limit'] - 1, $params['start'], $params['end']); + if(!empty($oldies)) + foreach($oldies as $oldie) + $data[] = $this->getInfo($oldie); + } } $this->getResult()->addValue(array( @@ -126,6 +97,44 @@ } } + /** + * Get result information for an image revision + * @param File f The image + * @return array Result array + */ + protected function getInfo($f) { + $vals = array(); + if($this->fld_timestamp) + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $f->getTimestamp()); + if($this->fld_user) { + $vals['user'] = $f->getUser(); + if(!$f->getUser('id')) + $vals['anon'] = ''; + } + if($this->fld_size) { + $vals['size'] = $f->getSize(); + $vals['width'] = $f->getWidth(); + $vals['height'] = $f->getHeight(); + } + if($this->fld_url) { + if($this->scale && !$f->isOld()) { + $vals['url'] = $f->createThumb($this->urlwidth, $this->urlheight); + } else { + $vals['url'] = $f->getURL(); + } + } + if($this->fld_comment) + $vals['comment'] = $f->getDescription(); + if($this->fld_sha1) + $vals['sha1'] = $f->getSha1(); + if($this->fld_metadata) { + $metadata = unserialize($f->getMetadata()); + $vals['metadata'] = $metadata ? $metadata : null; + $this->getResult()->setIndexedTagName_recursive($vals['metadata'], 'meta'); + } + return $vals; + } + protected function getAllowedParams() { return array ( 'prop' => array ( @@ -141,14 +150,38 @@ 'metadata' ) ), - 'history' => false, + 'limit' => array( + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_DFLT => 1, + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'start' => array( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'urlwidth' => array( + ApiBase :: PARAM_TYPE => 'integer', + ApiBase :: PARAM_DFLT => -1 + ), + 'urlheight' => array( + ApiBase :: PARAM_TYPE => 'integer', + ApiBase :: PARAM_DFLT => -1 + ) ); } protected function getParamDescription() { return array ( 'prop' => 'What image information to get.', - 'history' => 'Include upload history', + 'limit' => 'How many image revisions to return', + 'start' => 'Timestamp to start listing from', + 'end' => 'Timestamp to stop listing at', + 'urlwidth' => 'If iiprop=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 iiurlwidth. Cannot be used without iiurlwidth', ); } @@ -161,7 +194,7 @@ protected function getExamples() { return array ( 'api.php?action=query&titles=Image:Albert%20Einstein%20Head.jpg&prop=imageinfo', - 'api.php?action=query&titles=Image:Test.jpg&prop=imageinfo&iihistory&iiprop=timestamp|user|url', + 'api.php?action=query&titles=Image:Test.jpg&prop=imageinfo&iilimit=50&iiend=20071231235959&iiprop=timestamp|user|url', ); } Modified: branches/ApiEdit_Vodafone/includes/api/ApiRollback.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiRollback.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiRollback.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -43,32 +43,31 @@ $titleObj = NULL; if(!isset($params['title'])) - $this->dieUsage('The title parameter must be set', 'notitle'); + $this->dieUsageMsg(array('missingparam', 'title')); if(!isset($params['user'])) - $this->dieUsage('The user parameter must be set', 'nouser'); + $this->dieUsageMsg(array('missingparam', 'user')); if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - $titleObj = Title::newFromText($params['title']); if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + $this->dieUsageMsg(array('invalidtitle', $params['title'])); + if(!$titleObj->exists()) + $this->dieUsageMsg(array('notanarticle')); $username = User::getCanonicalName($params['user']); if(!$username) - $this->dieUsage("Invalid username ``{$params['user']}''", 'invaliduser'); + $this->dieUsageMsg(array('invaliduser', $params['user'])); $articleObj = new Article($titleObj); $summary = (isset($params['summary']) ? $params['summary'] : ""); $details = null; $dbw = wfGetDb(DB_MASTER); $dbw->begin(); - $retval = $articleObj->doRollback($username, $summary, $params['token'], $params['markbot'], &$details); + $retval = $articleObj->doRollback($username, $summary, $params['token'], $params['markbot'], $details); if(!empty($retval)) - // We don't care about multiple errors, just report the first one + // We don't care about multiple errors, just report one of them $this->dieUsageMsg(current($retval)); $dbw->commit(); @@ -87,6 +86,8 @@ $this->getResult()->addValue(null, $this->getModuleName(), $info); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'title' => null, Modified: branches/ApiEdit_Vodafone/includes/api/ApiUnblock.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiUnblock.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiUnblock.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -41,7 +41,7 @@ /** * Unblocks the specified user or provides the reason the unblock failed. - */ + */ public function execute() { global $wgUser; $this->getMain()->requestWriteMode(); @@ -55,47 +55,35 @@ } if(is_null($params['id']) && is_null($params['user'])) - $this->dieUsage('Either the id or the user parameter must be set', 'notarget'); + $this->dieUsageMsg(array('unblock-notarget')); if(!is_null($params['id']) && !is_null($params['user'])) - $this->dieUsage('The id and user parameters can\'t be used together', 'idanduser'); + $this->dieUsageMsg(array('unblock-idanduser')); if(is_null($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); + $this->dieUsageMsg(array('sessionfailure')); if(!$wgUser->isAllowed('block')) - $this->dieUsage('You don\'t have permission to unblock users', 'permissiondenied'); + $this->dieUsageMsg(array('cantunblock')); if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); + $this->dieUsageMsg(array('readonlytext')); $id = $params['id']; $user = $params['user']; - $reason = $params['reason']; + $reason = (is_null($params['reason']) ? '' : $params['reason']); $dbw = wfGetDb(DB_MASTER); $dbw->begin(); - $retval = IPUnblockForm::doUnblock(&$id, &$user, &$reason, &$range); + $retval = IPUnblockForm::doUnblock($id, $user, $reason, $range); + if(!empty($retval)) + $this->dieUsageMsg($retval); - switch($retval) - { - case IPUnblockForm::UNBLOCK_SUCCESS: - break; // We'll deal with that later - case IPUnblockForm::UNBLOCK_NO_SUCH_ID: - $this->dieUsage("There is no block with ID ``$id''", 'nosuchid'); - case IPUnblockForm::UNBLOCK_USER_NOT_BLOCKED: - $this->dieUsage("User ``$user'' is not blocked", 'notblocked'); - case IPUnblockForm::UNBLOCK_BLOCKED_AS_RANGE: - $this->dieUsage("IP address ``$user'' was blocked as part of range ``$range''. You can't unblock the IP invidually, but you can unblock the range as a whole.", 'blockedasrange'); - case IPUnblockForm::UNBLOCK_UNKNOWNERR: - $this->dieUsage("Unknown error", 'unknownerr'); - default: - $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($retval)"); - } $dbw->commit(); - $res['id'] = $id; $res['user'] = $user; $res['reason'] = $reason; $this->getResult()->addValue(null, $this->getModuleName(), $res); } + + public function mustBePosted() { return true; } protected function getAllowedParams() { return array ( Modified: branches/ApiEdit_Vodafone/includes/api/ApiUndelete.php =================================================================== --- branches/ApiEdit_Vodafone/includes/api/ApiUndelete.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/api/ApiUndelete.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -43,22 +43,22 @@ $titleObj = NULL; if(!isset($params['title'])) - $this->dieUsage('The title parameter must be set', 'notitle'); + $this->dieUsageMsg(array('missingparam', 'title')); if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); + $this->dieUsageMsg(array('missingparam', 'token')); if(!$wgUser->isAllowed('undelete')) - $this->dieUsage('You don\'t have permission to restore deleted revisions', 'permissiondenied'); + $this->dieUsageMsg(array('permdenied-undelete')); if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); + $this->dieUsageMsg(array('blockedtext')); if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); + $this->dieUsageMsg(array('readonlytext')); if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); + $this->dieUsageMsg(array('sessionfailure')); $titleObj = Title::newFromText($params['title']); if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + $this->dieUsageMsg(array('invalidtitle', $params['title'])); // Convert timestamps if(!is_array($params['timestamps'])) @@ -71,17 +71,9 @@ $dbw->begin(); $retval = $pa->undelete((isset($params['timestamps']) ? $params['timestamps'] : array()), $params['reason']); if(!is_array($retval)) - switch($retval) - { - case PageArchive::UNDELETE_NOTHINGRESTORED: - $this->dieUsage('No revisions could be restored', 'norevs'); - case PageArchive::UNDELETE_NOTAVAIL: - $this->dieUsage('Not all requested revisions could be found', 'revsnotfound'); - case PageArchive::UNDELETE_UNKNOWNERR: - $this->dieUsage('Undeletion failed with unknown error', 'unknownerror'); - } + $this->dieUsageMsg(array('cannotundelete')); + $dbw->commit(); - $info['title'] = $titleObj->getPrefixedText(); $info['revisions'] = $retval[0]; $info['fileversions'] = $retval[1]; @@ -89,6 +81,8 @@ $this->getResult()->addValue(null, $this->getModuleName(), $info); } + public function mustBePosted() { return true; } + protected function getAllowedParams() { return array ( 'title' => null, Modified: branches/ApiEdit_Vodafone/includes/filerepo/File.php =================================================================== --- branches/ApiEdit_Vodafone/includes/filerepo/File.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/filerepo/File.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -46,7 +46,7 @@ /** * The following member variables are not lazy-initialised */ - var $repo, $title, $lastError; + var $repo, $title, $lastError, $redirected; /** * Call this constructor from child classes @@ -220,6 +220,14 @@ public function getHeight( $page = 1 ) { return false; } /** + * Returns ID or name of user who uploaded the file + * STUB + * + * @param $type string 'text' or 'id' + */ + public function getUser( $type='text' ) { return null; } + + /** * Get the duration of a media file in seconds */ public function getLength() { @@ -628,6 +636,18 @@ } /** + * Return a fragment of the history of file. + * + * STUB + * @param $limit integer Limit of rows to return + * @param $start timestamp Only revisions older than $start will be returned + * @param $end timestamp Only revisions newer than $end will be returned + */ + function getHistory($limit = null, $start = null, $end = null) { + return false; + } + + /** * Return the history of this file, line by line. Starts with current version, * then old versions. Should return an object similar to an image/oldimage * database row. @@ -994,6 +1014,14 @@ } /** + * Get discription of file revision + * STUB + */ + function getDescription() { + return null; + } + + /** * Get the 14-character timestamp of the file upload, or false if * it doesn't exist */ @@ -1131,6 +1159,14 @@ return ''; } } + + function getRedirected() { + return $this->redirected; + } + + function redirectedFrom( $from ) { + $this->redirected = $from; + } } /** * Aliases for backwards compatibility with 1.6 Modified: branches/ApiEdit_Vodafone/includes/filerepo/FileRepo.php =================================================================== --- branches/ApiEdit_Vodafone/includes/filerepo/FileRepo.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/filerepo/FileRepo.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -90,6 +90,19 @@ if ( $img->exists() ) { return $img; } + + # Now try redirects + $redir = $this->checkRedirect( $title ); + if( $redir && $redir->getNamespace() == NS_IMAGE) { + $img = $this->newFile( $redir ); + if( !$img ) { + return false; + } + if( $img->exists() ) { + $img->redirectedFrom( $title->getText() ); + return $img; + } + } } /** @@ -400,5 +413,15 @@ * STUB */ function cleanupDeletedBatch( $storageKeys ) {} + + /** + * Checks if there is a redirect named as $title + * STUB + * + * @param Title $title Title of image + */ + function checkRedirect( $title ) { + return false; + } } Modified: branches/ApiEdit_Vodafone/includes/filerepo/LocalFile.php =================================================================== --- branches/ApiEdit_Vodafone/includes/filerepo/LocalFile.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/filerepo/LocalFile.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -5,7 +5,7 @@ /** * Bump this number when serialized cache records may be incompatible. */ -define( 'MW_FILE_VERSION', 4 ); +define( 'MW_FILE_VERSION', 6 ); /** * Class to represent a local file in the wiki's own database @@ -29,24 +29,26 @@ /**#@+ * @private */ - var $fileExists, # does the file file exist on disk? (loadFromXxx) - $historyLine, # Number of line to return by nextHistoryLine() (constructor) - $historyRes, # result of the query for the file's history (nextHistoryLine) - $width, # \ - $height, # | - $bits, # --- returned by getimagesize (loadFromXxx) - $attr, # / - $media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...) - $mime, # MIME type, determined by MimeMagic::guessMimeType - $major_mime, # Major mime type - $minor_mime, # Minor mime type - $size, # Size in bytes (loadFromXxx) - $metadata, # Handler-specific metadata - $timestamp, # Upload timestamp - $sha1, # SHA-1 base 36 content hash - $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) - $upgraded, # Whether the row was upgraded on load - $locked; # True if the image row is locked + var $fileExists, # does the file file exist on disk? (loadFromXxx) + $historyLine, # Number of line to return by nextHistoryLine() (constructor) + $historyRes, # result of the query for the file's history (nextHistoryLine) + $width, # \ + $height, # | + $bits, # --- returned by getimagesize (loadFromXxx) + $attr, # / + $media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...) + $mime, # MIME type, determined by MimeMagic::guessMimeType + $major_mime, # Major mime type + $minor_mime, # Minor mime type + $size, # Size in bytes (loadFromXxx) + $metadata, # Handler-specific metadata + $timestamp, # Upload timestamp + $sha1, # SHA-1 base 36 content hash + $user, $user_text, # User, who uploaded the file + $description, # Description of current revision of the file + $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) + $upgraded, # Whether the row was upgraded on load + $locked; # True if the image row is locked /**#@-*/ @@ -155,7 +157,7 @@ function getCacheFields( $prefix = 'img_' ) { static $fields = array( 'size', 'width', 'height', 'bits', 'media_type', - 'major_mime', 'minor_mime', 'metadata', 'timestamp', 'sha1' ); + 'major_mime', 'minor_mime', 'metadata', 'timestamp', 'sha1', 'user', 'user_text', 'description' ); static $results = array(); if ( $prefix == '' ) { return $fields; @@ -382,6 +384,20 @@ } /** + * Returns ID or name of user who uploaded the file + * + * @param $type string 'text' or 'id' + */ + function getUser($type='text') { + $this->load(); + if( $type == 'text' ) { + return $this->user_text; + } elseif( $type == 'id' ) { + return $this->user; + } + } + + /** * Get handler-specific metadata */ function getMetadata() { @@ -559,6 +575,28 @@ /** purgeDescription inherited */ /** purgeEverything inherited */ + function getHistory($limit = null, $start = null, $end = null) { + $dbr = $this->repo->getSlaveDB(); + $conds = $opts = array(); + $conds[] = "oi_name = " . $dbr->addQuotes( $this->title->getDBKey() ); + if( $start !== null ) { + $conds[] = "oi_timestamp < '" . $dbr->timestamp( $start ) . "'"; + } + if( $end !== null ) { + $conds[] = "oi_timestamp > '" . $dbr->timestamp( $end ). "'"; + } + if( $limit ) { + $opts['LIMIT'] = $limit; + } + $opts['ORDER BY'] = 'oi_timestamp DESC'; + $res = $dbr->select('oldimage', '*', $conds, __METHOD__, $opts); + $r = array(); + while( $row = $dbr->fetchObject($res) ) { + $r[] = OldLocalFile::newFromRow($row, $this->repo); + } + return $r; + } + /** * Return the history of this file, line by line. * starts with current version, then old versions. @@ -682,6 +720,9 @@ if ( !$props ) { $props = $this->repo->getFileProps( $this->getVirtualUrl() ); } + $props['description'] = $comment; + $props['user'] = $wgUser->getID(); + $props['user_text'] = $wgUser->getName(); $this->setProps( $props ); // Delete thumbnails and refresh the metadata cache @@ -968,6 +1009,11 @@ return $html; } + function getDescription() { + $this->load(); + return $this->description; + } + function getTimestamp() { $this->load(); return $this->timestamp; Modified: branches/ApiEdit_Vodafone/includes/filerepo/LocalRepo.php =================================================================== --- branches/ApiEdit_Vodafone/includes/filerepo/LocalRepo.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/filerepo/LocalRepo.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -62,4 +62,52 @@ } return $status; } + + /** + * Function link Title::getArticleID(). + * We can't say Title object, what database it should use, so we duplicate that function here. + */ + private function getArticleID( $title ) { + if( !$title instanceof Title ) { + return 0; + } + $dbr = $this->getSlaveDB(); + $id = $dbr->selectField( + 'page', // Table + 'page_id', //Field + array( //Conditions + 'page_namespace' => $title->getNamespace(), + 'page_title' => $title->getDbKey(), + ), + __METHOD__ //Function name + ); + return $id; + } + + function checkRedirect( $title ) { + global $wgFileRedirects; + if( !$wgFileRedirects ) { + return false; + } + + if( $title instanceof Title && $title->getNamespace() == NS_MEDIA ) { + $title = Title::makeTitle( NS_IMAGE, $title->getText() ); + } + + $id = $this->getArticleID( $title ); + if( !$id ) { + return false; + } + $dbr = $this->getSlaveDB(); + $row = $dbr->selectRow( + 'redirect', + array( 'rd_title', 'rd_namespace' ), + array( 'rd_from' => $id ), + __METHOD__ + ); + if( !$row ) { + return false; + } + return Title::makeTitle( $row->rd_namespace, $row->rd_title ); + } } Modified: branches/ApiEdit_Vodafone/includes/filerepo/RepoGroup.php =================================================================== --- branches/ApiEdit_Vodafone/includes/filerepo/RepoGroup.php 2008-01-20 18:39:49 UTC (rev 29995) +++ branches/ApiEdit_Vodafone/includes/filerepo/RepoGroup.php 2008-01-20 18:41:22 UTC (rev 29996) @@ -77,6 +77,27 @@ } /** + * Interface for FileRepo::checkRedirect() + */ + function checkRedirect( $title ) { + if ( !$this->reposInitialised ) { + $this->initialiseRepos(); + } + + $redir = $this->localRepo->checkRedirect( $title ); + if( $redir ) { + return $redir; + } + foreach ( $this->foreignRepos as $repo ) { + $redir = $repo->checkRedirect( $title ); + if ( $redir ) { + return $redir; + } + } + return false; + } + + /** * Get the repo instance with a given key. */ function getRepo( $index ) { _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS[at]lists.wikimedia.org http://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs
|