public function setBits($bits) { $dbw = wfGetDB(DB_MASTER); // Update revision table $dbw->update('revision', array('rev_deleted' => $bits), array('rev_id' => $this->revision->getId(), 'rev_page' => $this->revision->getPage(), 'rev_deleted' => $this->getBits()), __METHOD__); if (!$dbw->affectedRows()) { // Concurrent fail! return false; } // Update recentchanges table $dbw->update('recentchanges', array('rc_deleted' => $bits, 'rc_patrolled' => 1), array('rc_this_oldid' => $this->revision->getId(), 'rc_timestamp' => $dbw->timestamp($this->revision->getTimestamp())), __METHOD__); return true; }
protected function assertRevEquals(Revision $orig, Revision $rev = null) { $this->assertNotNull($rev, 'missing revision'); $this->assertEquals($orig->getId(), $rev->getId()); $this->assertEquals($orig->getPage(), $rev->getPage()); $this->assertEquals($orig->getTimestamp(), $rev->getTimestamp()); $this->assertEquals($orig->getUser(), $rev->getUser()); $this->assertEquals($orig->getSha1(), $rev->getSha1()); }
/** * Executes the real stuff. No checks done! * @param User $user * @param Revision $revision * @param null|string $comment * @return Bool, whether the action was recorded. */ public static function doReview(User $user, Revision $revision, $comment = null) { $dbw = wfGetDB(DB_MASTER); $table = 'translate_reviews'; $row = array('trr_user' => $user->getId(), 'trr_page' => $revision->getPage(), 'trr_revision' => $revision->getId()); $options = array('IGNORE'); $dbw->insert($table, $row, __METHOD__, $options); if (!$dbw->affectedRows()) { return false; } $title = $revision->getTitle(); $entry = new ManualLogEntry('translationreview', 'message'); $entry->setPerformer($user); $entry->setTarget($title); $entry->setComment($comment); $entry->setParameters(array('4::revision' => $revision->getId())); $logid = $entry->insert(); $entry->publish($logid); $handle = new MessageHandle($title); Hooks::run('TranslateEventTranslationReview', array($handle)); return true; }
/** * Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect * * @return int The old id for the request */ public function getOldIDFromRequest() { global $wgRequest; $this->mRedirectUrl = false; $oldid = $wgRequest->getIntOrNull('oldid'); if ($oldid === null) { return 0; } if ($oldid !== 0) { # Load the given revision and check whether the page is another one. # In that case, update this instance to reflect the change. $this->mRevision = Revision::newFromId($oldid); if ($this->mRevision !== null) { // Revision title doesn't match the page title given? if ($this->mPage->getID() != $this->mRevision->getPage()) { $function = array(get_class($this->mPage), 'newFromID'); $this->mPage = call_user_func($function, $this->mRevision->getPage()); } } } if ($wgRequest->getVal('direction') == 'next') { $nextid = $this->getTitle()->getNextRevisionID($oldid); if ($nextid) { $oldid = $nextid; $this->mRevision = null; } else { $this->mRedirectUrl = $this->getTitle()->getFullURL('redirect=no'); } } elseif ($wgRequest->getVal('direction') == 'prev') { $previd = $this->getTitle()->getPreviousRevisionID($oldid); if ($previd) { $oldid = $previd; $this->mRevision = null; } } return $oldid; }
/** * saveComplete -- hook * * @static * @access public * * @param WikiPage $oArticle, * @param User $User * * @author Piotr Molski (MoLi) * @return true */ public static function saveComplete(&$oArticle, &$oUser, $text, $summary, $minor, $undef1, $undef2, &$flags, Revision $oRevision, &$status, $baseRevId) { global $wgCityId; wfProfileIn(__METHOD__); $revId = $pageId = 0; if (is_object($oArticle) && $oUser instanceof User) { # revision if ($oRevision instanceof Revision) { $revId = $oRevision->getId(); $pageId = $oRevision->getPage(); } if (empty($revId)) { $revId = $oArticle->getTitle()->getLatestRevID(Title::GAID_FOR_UPDATE); } # article if (empty($pageId) || $pageId < 0) { $pageId = $oArticle->getID(); } if ($revId > 0 && $pageId > 0) { $key = isset($status->value['new']) && $status->value['new'] == 1 ? 'create' : 'edit'; $oScribeProducer = new ScribeProducer($key, $pageId, $revId, 0, !empty($undef1) ? 1 : 0); if (is_object($oScribeProducer)) { $oScribeProducer->send_log(); } } else { Wikia::log(__METHOD__, "error", "Cannot send log via scribe ({$wgCityId}): revision not found for page: {$pageId}"); } } else { $isArticle = is_object($oArticle); $isUser = is_object($oUser); Wikia::log(__METHOD__, "error", "Cannot send log via scribe ({$wgCityId}): invalid user: {$isUser}, invalid article: {$isArticle}"); } wfProfileOut(__METHOD__); return true; }
/** * Update the revision's rev_deleted field * @param Revision $rev * @param int $bitfield new rev_deleted bitfield value */ function updateRevision($rev, $bitfield) { $this->dbw->update('revision', array('rev_deleted' => $bitfield), array('rev_id' => $rev->getId(), 'rev_page' => $rev->getPage()), __METHOD__); }
/** * revisionInsertComplete * * static method called as hook * * @static * @access public * * @param Revision $revision revision object * @param string $url url to external object * @param string $flags flags for this revision * * @return true means process other hooks */ public static function revisionInsertComplete(&$revision, $url, $flags) { global $wgUser, $wgCityId, $wgCommandLineMode, $wgSharedDB, $wgErrorLog, $wgMemc, $wgRequest; wfProfileIn(__METHOD__); /** * Do not create task when DB is locked (rt#12229) * Do not create task when we are in $wgCommandLineMode */ $oldValue = $wgErrorLog; $wgErrorLog = true; if (!wfReadOnly() && !$wgCommandLineMode) { /** * Revision has valid Title field but sometimes not filled */ $Title = $revision->getTitle(); if (!$Title) { $Title = Title::newFromId($revision->getPage(), Title::GAID_FOR_UPDATE); $revision->setTitle($Title); } /** * get groups for user rt#12215 */ $groups = $wgUser->getEffectiveGroups(); $invalid = array("bot" => true, "bot-global" => true, "staff" => true, "helper" => true, "sysop" => true, "bureaucrat" => true, "vstf" => true); $canWelcome = true; foreach ($groups as $group) { if (isset($invalid[$group]) && $invalid[$group]) { $canWelcome = false; Wikia::log(__METHOD__, $wgUser->getId(), "Skip welcome, user is at least in group: " . $group); break; } } /** * put possible welcomer into memcached, RT#14067 */ if ($wgUser->getId() && self::isWelcomer($wgUser)) { // BugId:41817 - if ( 1 == $wgUser->getId() ) { notify Mix } if (1 == $wgUser->getId()) { $oTo = $oFrom = new MailAddress('*****@*****.**'); UserMailer::send($oTo, $oFrom, 'BugId:41817 Occurrence Report', sprintf("File: %s\nLine: %s, Date: %s\nOutput: %s", __FILE__, __LINE__, date('Y-m-d H:i:s'), var_export($wgUser->getId(), true))); } $wgMemc->set(wfMemcKey("last-sysop-id"), $wgUser->getId(), 86400); Wikia::log(__METHOD__, $wgUser->getId(), "Store possible welcomer in memcached"); } if ($Title && $canWelcome && !empty($wgSharedDB)) { Wikia::log(__METHOD__, "title", $Title->getFullURL()); $welcomer = trim(wfMsgForContent("welcome-user")); Wikia::log(__METHOD__, "welcomer", $welcomer); if ($welcomer !== "@disabled" && $welcomer !== "-") { /** * check if talk page for wgUser exists * * @todo check editcount for user */ Wikia::log(__METHOD__, "user", $wgUser->getName()); $talkPage = $wgUser->getUserPage()->getTalkPage(); if ($talkPage) { $talkArticle = new Article($talkPage, 0); if (!self::isPosted($talkArticle, $wgUser)) { $welcomeJob = new HAWelcomeJob($Title, array("is_anon" => $wgUser->isAnon(), "user_id" => $wgUser->getId(), "user_ip" => $wgRequest->getIP(), "user_name" => $wgUser->getName())); $welcomeJob->insert(); Wikia::log(__METHOD__, "job"); /** * inform task manager */ $Task = new HAWelcomeTask(); $taskId = $Task->createTask(array("city_id" => $wgCityId), TASK_QUEUED); Wikia::log(__METHOD__, "task", $taskId); } else { Wikia::log(__METHOD__, "exists", sprintf("Talk page for user %s already exits", $wgUser->getName())); } } } else { Wikia::log(__METHOD__, "disabled"); } } } $wgErrorLog = $oldValue; wfProfileOut(__METHOD__); return true; }
public function execute() { $params = $this->extractRequestParams(false); // If any of those parameters are used, work in 'enumeration' mode. // Enum mode can only be used when exactly one page is provided. // Enumerating revisions on multiple pages make it extremely // difficult to manage continuations and require additional SQL indexes $enumRevMode = !is_null($params['user']) || !is_null($params['excludeuser']) || !is_null($params['limit']) || !is_null($params['startid']) || !is_null($params['endid']) || $params['dir'] === 'newer' || !is_null($params['start']) || !is_null($params['end']); $pageSet = $this->getPageSet(); $pageCount = $pageSet->getGoodTitleCount(); $revCount = $pageSet->getRevisionCount(); // Optimization -- nothing to do if ($revCount === 0 && $pageCount === 0) { return; } if ($revCount > 0 && $enumRevMode) { $this->dieUsage('The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).', 'revids'); } if ($pageCount > 1 && $enumRevMode) { $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start and end parameters may only be used on a single page.', 'multpages'); } if (!is_null($params['diffto'])) { if ($params['diffto'] == 'cur') { $params['diffto'] = 0; } if ((!ctype_digit($params['diffto']) || $params['diffto'] < 0) && $params['diffto'] != 'prev' && $params['diffto'] != 'next') { $this->dieUsage('rvdiffto must be set to a non-negative number, "prev", "next" or "cur"', 'diffto'); } // Check whether the revision exists and is readable, // DifferenceEngine returns a rather ambiguous empty // string if that's not the case if ($params['diffto'] != 0) { $difftoRev = Revision::newFromID($params['diffto']); if (!$difftoRev) { $this->dieUsageMsg(array('nosuchrevid', $params['diffto'])); } if (!$difftoRev->userCan(Revision::DELETED_TEXT)) { $this->setWarning("Couldn't diff to r{$difftoRev->getID()}: content is hidden"); $params['diffto'] = null; } } } $this->addTables('revision'); $this->addFields(Revision::selectFields()); $this->addTables('page'); $this->addWhere('page_id = rev_page'); $prop = array_flip($params['prop']); // Optional fields $this->fld_ids = isset($prop['ids']); // $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed? $this->fld_flags = isset($prop['flags']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_comment = isset($prop['comment']); $this->fld_size = isset($prop['size']); $this->fld_user = isset($prop['user']); $this->token = $params['token']; $this->diffto = $params['diffto']; if (!is_null($this->token) || $pageCount > 0) { $this->addFields(Revision::selectPageFields()); } if (isset($prop['content'])) { // For each page we will request, the user must have read rights for that page foreach ($pageSet->getGoodTitles() as $title) { if (!$title->userCanRead()) { $this->dieUsage('The current user is not allowed to read ' . $title->getPrefixedText(), 'accessdenied'); } } $this->addTables('text'); $this->addWhere('rev_text_id=old_id'); $this->addFields('old_id'); $this->addFields(Revision::selectTextFields()); $this->fld_content = true; $this->expandTemplates = $params['expandtemplates']; $this->generateXML = $params['generatexml']; if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } } $userMax = $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1; $botMax = $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2; $limit = $params['limit']; if ($limit == 'max') { $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $this->getResult()->addValue('limits', $this->getModuleName(), $limit); } if ($enumRevMode) { // This is mostly to prevent parameter errors (and optimize SQL?) if (!is_null($params['startid']) && !is_null($params['start'])) { $this->dieUsage('start and startid cannot be used together', 'badparams'); } if (!is_null($params['endid']) && !is_null($params['end'])) { $this->dieUsage('end and endid cannot be used together', 'badparams'); } if (!is_null($params['user']) && !is_null($params['excludeuser'])) { $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); } // This code makes an assumption that sorting by rev_id and rev_timestamp produces // the same result. This way users may request revisions starting at a given time, // but to page through results use the rev_id returned after each page. // Switching to rev_id removes the potential problem of having more than // one row with the same timestamp for the same page. // The order needs to be the same as start parameter to avoid SQL filesort. if (is_null($params['startid']) && is_null($params['endid'])) { $this->addWhereRange('rev_timestamp', $params['dir'], $params['start'], $params['end']); } else { $this->addWhereRange('rev_id', $params['dir'], $params['startid'], $params['endid']); // One of start and end can be set // If neither is set, this does nothing $this->addWhereRange('rev_timestamp', $params['dir'], $params['start'], $params['end'], false); } // must manually initialize unset limit if (is_null($limit)) { $limit = 10; } $this->validateLimit('limit', $limit, 1, $userMax, $botMax); // There is only one ID, use it $this->addWhereFld('rev_page', reset(array_keys($pageSet->getGoodTitles()))); if (!is_null($params['user'])) { $this->addWhereFld('rev_user_text', $params['user']); } elseif (!is_null($params['excludeuser'])) { $this->addWhere('rev_user_text != ' . $this->getDB()->addQuotes($params['excludeuser'])); } if (!is_null($params['user']) || !is_null($params['excludeuser'])) { // Paranoia: avoid brute force searches (bug 17342) $this->addWhere('rev_deleted & ' . Revision::DELETED_USER . ' = 0'); } } elseif ($revCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $revs = $pageSet->getRevisionIDs(); if (self::truncateArray($revs, $max)) { $this->setWarning("Too many values supplied for parameter 'revids': the limit is {$max}"); } // Get all revision IDs $this->addWhereFld('rev_id', array_keys($revs)); if (!is_null($params['continue'])) { $this->addWhere("rev_id >= '" . intval($params['continue']) . "'"); } $this->addOption('ORDER BY', 'rev_id'); // assumption testing -- we should never get more then $revCount rows. $limit = $revCount; } elseif ($pageCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $titles = $pageSet->getGoodTitles(); if (self::truncateArray($titles, $max)) { $this->setWarning("Too many values supplied for parameter 'titles': the limit is {$max}"); } // When working in multi-page non-enumeration mode, // limit to the latest revision only $this->addWhere('page_id=rev_page'); $this->addWhere('page_latest=rev_id'); // Get all page IDs $this->addWhereFld('page_id', array_keys($titles)); // Every time someone relies on equality propagation, god kills a kitten :) $this->addWhereFld('rev_page', array_keys($titles)); if (!is_null($params['continue'])) { $cont = explode('|', $params['continue']); if (count($cont) != 2) { $this->dieUsage("Invalid continue param. You should pass the original " . "value returned by the previous query", "_badcontinue"); } $pageid = intval($cont[0]); $revid = intval($cont[1]); $this->addWhere("rev_page > '{$pageid}' OR " . "(rev_page = '{$pageid}' AND " . "rev_id >= '{$revid}')"); } $this->addOption('ORDER BY', 'rev_page, rev_id'); // assumption testing -- we should never get more then $pageCount rows. $limit = $pageCount; } else { ApiBase::dieDebug(__METHOD__, 'param validation?'); } $this->addOption('LIMIT', $limit + 1); $data = array(); $count = 0; $res = $this->select(__METHOD__); $db = $this->getDB(); while ($row = $db->fetchObject($res)) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... if (!$enumRevMode) { ApiBase::dieDebug(__METHOD__, 'Got more rows then expected'); } // bug report $this->setContinueEnumParameter('startid', intval($row->rev_id)); break; } $revision = new Revision($row); // $fit = $this->addPageSubItem($revision->getPage(), $this->extractRowInfo($revision), 'rev'); if (!$fit) { if ($enumRevMode) { $this->setContinueEnumParameter('startid', intval($row->rev_id)); } else { if ($revCount > 0) { $this->setContinueEnumParameter('continue', intval($row->rev_id)); } else { $this->setContinueEnumParameter('continue', intval($row->rev_page) . '|' . intval($row->rev_id)); } } break; } } $db->freeResult($res); }
/** * Page moving and page protection (and possibly other things) creates null * revisions. These revisions re-use the previous text already stored in * the database. Those however do not trigger re-parsing of the page and * thus the ready tag is not updated. This watches for new revisions, * checks if they reuse existing text, checks whether the parent version * is the latest version and has a ready tag. If that is the case, * also adds a ready tag for the new revision (which is safe, because * the text hasn't changed). The interface will say that there has been * a change, but shows no change in the content. This lets the user to * update the translation pages in the case, the non-text changes affect * the rendering of translation pages. I'm not aware of any such cases * at the moment. * Hook: RevisionInsertComplete * @since 2012-05-08 */ public static function updateTranstagOnNullRevisions(Revision $rev, $text, $flags) { $title = $rev->getTitle(); $newRevId = $rev->getId(); $oldRevId = $rev->getParentId(); $newTextId = $rev->getTextId(); /* This hook doesn't provide any way to detech null revisions * without extra query */ $dbw = wfGetDB(DB_MASTER); $table = 'revision'; $field = 'rev_text_id'; $conds = array('rev_page' => $rev->getPage(), 'rev_id' => $oldRevId); // FIXME: optimize away this query. Bug T38588. $oldTextId = $dbw->selectField($table, $field, $conds, __METHOD__); if (strval($newTextId) !== strval($oldTextId)) { // Not a null revision, bail out. return true; } $page = TranslatablePage::newFromTitle($title); if ($page->getReadyTag() === $oldRevId) { $page->addReadyTag($newRevId); } return true; }
/** * revisionInsertComplete * * static method called as hook * * @static * @access public * * @param Revision $revision revision object * @param string $url url to external object * @param string $flags flags for this revision * * @return true means process other hooks */ public static function revisionInsertComplete(&$revision, $url, $flags) { global $wgUser, $wgCityId, $wgCommandLineMode, $wgSharedDB, $wgErrorLog, $wgMemc, $wgRequest; //do nothing if the user clicked 'undo' if ($wgRequest->getVal('wpUndoEdit')) { return true; } wfProfileIn(__METHOD__); /* first edit? */ //if (User::edits($wgUser->getID()) == 1) { /** * Do not create task when DB is locked (rt#12229) * Do not create task when we are in $wgCommandLineMode */ $oldValue = $wgErrorLog; $wgErrorLog = true; if (!wfReadOnly() && !$wgCommandLineMode) { wfLoadExtensionMessages("HAWelcome"); /** * Revision has valid Title field but sometimes not filled */ $Title = $revision->getTitle(); if (!$Title) { $Title = Title::newFromId($revision->getPage(), GAID_FOR_UPDATE); $revision->setTitle($Title); } /** * get groups for user rt#12215 */ $groups = $wgUser->getEffectiveGroups(); $invalid = array("bot" => true, "staff" => true, "helper" => true, "sysop" => true, "bureaucrat" => true, "vstf" => true); $canWelcome = true; foreach ($groups as $group) { if (isset($invalid[$group]) && $invalid[$group]) { $canWelcome = false; break; } } /** * put possible welcomer into memcached, RT#14067 */ if ($wgUser->getId() && self::isWelcomer($wgUser)) { //$wgMemc->set( wfMemcKey( "last-sysop-id" ), $wgUser->getId(), 86400 ); $wgMemc->set(wfMemcKey("last-sysop-id"), $wgUser->getId(), 3600); } if ($Title && $canWelcome && !empty($wgSharedDB)) { $welcomer = trim(wfMsgForContent("welcome-user")); if ($welcomer !== "@disabled" && $welcomer !== "-") { /** * check if talk page for wgUser exists * * @todo check editcount for user */ $talkPage = $wgUser->getUserPage()->getTalkPage(); if ($talkPage) { $talkArticle = new Article($talkPage, 0); if (!$talkArticle->exists()) { //run the talk page stuff self::runEditThanks($Title); } } } } } //} $wgErrorLog = $oldValue; wfProfileOut(__METHOD__); return true; }
/** * Check if a user reverted himself to the stable version */ protected static function isSelfRevertToStable(Revision $rev, $srev, $baseRevId, $user) { if (!$srev || $baseRevId != $srev->getRevId()) { return false; // user reports they are not the same } $dbw = wfGetDB(DB_MASTER); # Such a revert requires 1+ revs between it and the stable $revertedRevs = $dbw->selectField('revision', '1', array('rev_page' => $rev->getPage(), 'rev_id > ' . intval($baseRevId), 'rev_id < ' . intval($rev->getId()), 'rev_user_text' => $user->getName()), __METHOD__); if (!$revertedRevs) { return false; // can't be a revert } # Check that this user is ONLY reverting his/herself. $otherUsers = $dbw->selectField('revision', '1', array('rev_page' => $rev->getPage(), 'rev_id > ' . intval($baseRevId), 'rev_user_text != ' . $dbw->addQuotes($user->getName())), __METHOD__); if ($otherUsers) { return false; // only looking for self-reverts } # Confirm the text because we can't trust this user. return $rev->getSha1() === $srev->getRevision()->getSha1(); }
public function execute() { $params = $this->extractRequestParams(false); // If any of those parameters are used, work in 'enumeration' mode. // Enum mode can only be used when exactly one page is provided. // Enumerating revisions on multiple pages make it extremely // difficult to manage continuations and require additional SQL indexes $enumRevMode = !is_null($params['user']) || !is_null($params['excludeuser']) || !is_null($params['limit']) || !is_null($params['startid']) || !is_null($params['endid']) || $params['dir'] === 'newer' || !is_null($params['start']) || !is_null($params['end']); $pageSet = $this->getPageSet(); $pageCount = $pageSet->getGoodTitleCount(); $revCount = $pageSet->getRevisionCount(); // Optimization -- nothing to do if ($revCount === 0 && $pageCount === 0) { return; } if ($revCount > 0 && $enumRevMode) { $this->dieUsage('The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).', 'revids'); } if ($pageCount > 1 && $enumRevMode) { $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start and end parameters may only be used on a single page.', 'multpages'); } $this->addTables('revision'); $this->addFields(Revision::selectFields()); $this->addTables('page'); $this->addWhere('page_id = rev_page'); $prop = array_flip($params['prop']); // Optional fields $this->fld_ids = isset($prop['ids']); // $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed? $this->fld_flags = isset($prop['flags']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_comment = isset($prop['comment']); $this->fld_size = isset($prop['size']); $this->fld_user = isset($prop['user']); $this->token = $params['token']; if (!is_null($this->token) || $pageCount > 0) { $this->addFields(Revision::selectPageFields()); } if (isset($prop['content'])) { // For each page we will request, the user must have read rights for that page foreach ($pageSet->getGoodTitles() as $title) { if (!$title->userCanRead()) { $this->dieUsage('The current user is not allowed to read ' . $title->getPrefixedText(), 'accessdenied'); } } $this->addTables('text'); $this->addWhere('rev_text_id=old_id'); $this->addFields('old_id'); $this->addFields(Revision::selectTextFields()); $this->fld_content = true; $this->expandTemplates = $params['expandtemplates']; $this->generateXML = $params['generatexml']; if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } } $userMax = $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1; $botMax = $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2; $limit = $params['limit']; if ($limit == 'max') { $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $this->getResult()->addValue('limits', $this->getModuleName(), $limit); } if ($enumRevMode) { // This is mostly to prevent parameter errors (and optimize SQL?) if (!is_null($params['startid']) && !is_null($params['start'])) { $this->dieUsage('start and startid cannot be used together', 'badparams'); } if (!is_null($params['endid']) && !is_null($params['end'])) { $this->dieUsage('end and endid cannot be used together', 'badparams'); } if (!is_null($params['user']) && !is_null($params['excludeuser'])) { $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); } // This code makes an assumption that sorting by rev_id and rev_timestamp produces // the same result. This way users may request revisions starting at a given time, // but to page through results use the rev_id returned after each page. // Switching to rev_id removes the potential problem of having more than // one row with the same timestamp for the same page. // The order needs to be the same as start parameter to avoid SQL filesort. if (is_null($params['startid']) && is_null($params['endid'])) { $this->addWhereRange('rev_timestamp', $params['dir'], $params['start'], $params['end']); } else { $this->addWhereRange('rev_id', $params['dir'], $params['startid'], $params['endid']); } // must manually initialize unset limit if (is_null($limit)) { $limit = 10; } $this->validateLimit('limit', $limit, 1, $userMax, $botMax); // There is only one ID, use it $this->addWhereFld('rev_page', current(array_keys($pageSet->getGoodTitles()))); if (!is_null($params['user'])) { $this->addWhereFld('rev_user_text', $params['user']); } elseif (!is_null($params['excludeuser'])) { $this->addWhere('rev_user_text != ' . $this->getDB()->addQuotes($params['excludeuser'])); } } elseif ($revCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $revs = $pageSet->getRevisionIDs(); if (self::truncateArray($revs, $max)) { $this->setWarning("Too many values supplied for parameter 'revids': the limit is {$max}"); } // Get all revision IDs $this->addWhereFld('rev_id', array_keys($revs)); // assumption testing -- we should never get more then $revCount rows. $limit = $revCount; } elseif ($pageCount > 0) { $max = $this->getMain()->canApiHighLimits() ? $botMax : $userMax; $titles = $pageSet->getGoodTitles(); if (self::truncateArray($titles, $max)) { $this->setWarning("Too many values supplied for parameter 'titles': the limit is {$max}"); } // When working in multi-page non-enumeration mode, // limit to the latest revision only $this->addWhere('page_id=rev_page'); $this->addWhere('page_latest=rev_id'); // Get all page IDs $this->addWhereFld('page_id', array_keys($titles)); // assumption testing -- we should never get more then $pageCount rows. $limit = $pageCount; } else { ApiBase::dieDebug(__METHOD__, 'param validation?'); } $this->addOption('LIMIT', $limit + 1); $data = array(); $count = 0; $res = $this->select(__METHOD__); $db = $this->getDB(); while ($row = $db->fetchObject($res)) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... if (!$enumRevMode) { ApiBase::dieDebug(__METHOD__, 'Got more rows then expected'); } // bug report $this->setContinueEnumParameter('startid', intval($row->rev_id)); break; } $revision = new Revision($row); $this->getResult()->addValue(array('query', 'pages', $revision->getPage(), 'revisions'), null, $this->extractRowInfo($revision)); } $db->freeResult($res); // Ensure that all revisions are shown as '<rev>' elements $result = $this->getResult(); if ($result->getIsRawMode()) { $data =& $result->getData(); foreach ($data['query']['pages'] as &$page) { if (is_array($page) && array_key_exists('revisions', $page)) { $result->setIndexedTagName($page['revisions'], 'rev'); } } } }