diff options
Diffstat (limited to 'includes/api/ApiQueryDeletedrevs.php')
-rw-r--r-- | includes/api/ApiQueryDeletedrevs.php | 183 |
1 files changed, 144 insertions, 39 deletions
diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index 408421c4..bdbe05e8 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -56,13 +56,27 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $fld_len = isset($prop['len']); $fld_content = isset($prop['content']); $fld_token = isset($prop['token']); - + $result = $this->getResult(); $pageSet = $this->getPageSet(); $titles = $pageSet->getTitles(); $data = array(); + + // This module operates in three modes: + // 'revs': List deleted revs for certain titles + // 'user': List deleted revs by a certain user + // 'all': List all deleted revs + $mode = 'all'; + if(count($titles) > 0) + $mode = 'revs'; + else if(!is_null($params['user'])) + $mode = 'user'; + + if(!is_null($params['user']) && !is_null($params['excludeuser'])) + $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); $this->addTables('archive'); + $this->addWhere('ar_deleted = 0'); $this->addFields(array('ar_title', 'ar_namespace', 'ar_timestamp')); if($fld_revid) $this->addFields('ar_rev_id'); @@ -102,34 +116,88 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $token = $wgUser->editToken(); // We need a custom WHERE clause that matches all titles. - if(count($titles) > 0) + if($mode == 'revs') { $lb = new LinkBatch($titles); $where = $lb->constructSet('ar', $db); $this->addWhere($where); - } else { - $this->dieUsage('You have to specify a page title or titles'); + } + elseif($mode == 'all') + { + $this->addWhereFld('ar_namespace', $params['namespace']); + if(!is_null($params['from'])) + { + $from = $this->getDB()->strencode($this->titleToKey($params['from'])); + $this->addWhere("ar_title >= '$from'"); + } + } + + if(!is_null($params['user'])) { + $this->addWhereFld('ar_user_text', $params['user']); + } elseif(!is_null($params['excludeuser'])) { + $this->addWhere('ar_user_text != ' . + $this->getDB()->addQuotes($params['excludeuser'])); + } + + if(!is_null($params['continue']) && ($mode == 'all' || $mode == 'revs')) + { + $cont = explode('|', $params['continue']); + if(count($cont) != 3) + $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "badcontinue"); + $ns = intval($cont[0]); + $title = $this->getDB()->strencode($this->titleToKey($cont[1])); + $ts = $this->getDB()->strencode($cont[2]); + $op = ($params['dir'] == 'newer' ? '>' : '<'); + $this->addWhere("ar_namespace $op $ns OR " . + "(ar_namespace = $ns AND " . + "(ar_title $op '$title' OR " . + "(ar_title = '$title' AND " . + "ar_timestamp = '$ts')))"); } $this->addOption('LIMIT', $limit + 1); - $this->addWhereRange('ar_timestamp', $params['dir'], $params['start'], $params['end']); + $this->addOption('USE INDEX', array('archive' => ($mode == 'user' ? 'usertext_timestamp' : 'name_title_timestamp'))); + if($mode == 'all') + { + if($params['unique']) + { + $this->addOption('GROUP BY', 'ar_title'); + $this->addOption('ORDER BY', 'ar_title'); + } + else + $this->addOption('ORDER BY', 'ar_title, ar_timestamp'); + } + else + { + if($mode == 'revs') + { + // Sort by ns and title in the same order as timestamp for efficiency + $this->addWhereRange('ar_namespace', $params['dir'], null, null); + $this->addWhereRange('ar_title', $params['dir'], null, null); + } + $this->addWhereRange('ar_timestamp', $params['dir'], $params['start'], $params['end']); + } $res = $this->select(__METHOD__); - $pages = array(); + $pageMap = array(); // Maps ns&title to (fake) pageid $count = 0; - // First populate the $pages array + $newPageID = 0; while($row = $db->fetchObject($res)) { if(++$count > $limit) { // We've had enough - $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->ar_timestamp)); + if($mode == 'all' || $mode == 'revs') + $this->setContinueEnumParameter('continue', intval($row->ar_namespace) . '|' . + $this->keyToTitle($row->ar_title) . '|' . $row->ar_timestamp); + else + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->ar_timestamp)); break; } $rev = array(); $rev['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ar_timestamp); if($fld_revid) - $rev['revid'] = $row->ar_rev_id; + $rev['revid'] = intval($row->ar_rev_id); if($fld_user) $rev['user'] = $row->ar_user_text; if($fld_comment) @@ -142,31 +210,38 @@ class ApiQueryDeletedrevs extends ApiQueryBase { if($fld_content) ApiResult::setContent($rev, Revision::getRevisionText($row)); - $t = Title::makeTitle($row->ar_namespace, $row->ar_title); - if(!isset($pages[$t->getPrefixedText()])) + if(!isset($pageMap[$row->ar_namespace][$row->ar_title])) { - $pages[$t->getPrefixedText()] = array( - 'title' => $t->getPrefixedText(), - 'ns' => intval($row->ar_namespace), - 'revisions' => array($rev) - ); + $pageID = $newPageID++; + $pageMap[$row->ar_namespace][$row->ar_title] = $pageID; + $t = Title::makeTitle($row->ar_namespace, $row->ar_title); + $a['revisions'] = array($rev); + $result->setIndexedTagName($a['revisions'], 'rev'); + ApiQueryBase::addTitleInfo($a, $t); if($fld_token) - $pages[$t->getPrefixedText()]['token'] = $token; + $a['token'] = $token; + $fit = $result->addValue(array('query', $this->getModuleName()), $pageID, $a); } else - $pages[$t->getPrefixedText()]['revisions'][] = $rev; + { + $pageID = $pageMap[$row->ar_namespace][$row->ar_title]; + $fit = $result->addValue( + array('query', $this->getModuleName(), $pageID, 'revisions'), + null, $rev); + } + if(!$fit) + { + if($mode == 'all' || $mode == 'revs') + $this->setContinueEnumParameter('continue', intval($row->ar_namespace) . '|' . + $this->keyToTitle($row->ar_title) . '|' . $row->ar_timestamp); + else + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->ar_timestamp)); + break; + } } $db->freeResult($res); - - // We don't want entire pagenames as keys, so let's make this array indexed - foreach($pages as $page) - { - $result->setIndexedTagName($page['revisions'], 'rev'); - $data[] = $page; - } - $result->setIndexedTagName($data, 'page'); - $result->addValue('query', $this->getModuleName(), $data); - } + $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'page'); + } public function getAllowedParams() { return array ( @@ -183,6 +258,19 @@ class ApiQueryDeletedrevs extends ApiQueryBase { ), ApiBase :: PARAM_DFLT => 'older' ), + 'from' => null, + 'continue' => null, + 'unique' => false, + 'user' => array( + ApiBase :: PARAM_TYPE => 'user' + ), + 'excludeuser' => array( + ApiBase :: PARAM_TYPE => 'user' + ), + 'namespace' => array( + ApiBase :: PARAM_TYPE => 'namespace', + ApiBase :: PARAM_DFLT => 0, + ), 'limit' => array( ApiBase :: PARAM_DFLT => 10, ApiBase :: PARAM_TYPE => 'limit', @@ -202,34 +290,51 @@ class ApiQueryDeletedrevs extends ApiQueryBase { 'token' ), ApiBase :: PARAM_ISMULTI => true - ) + ), ); } public function getParamDescription() { return array ( - 'start' => 'The timestamp to start enumerating from', - 'end' => 'The timestamp to stop enumerating at', - 'dir' => 'The direction in which to enumerate', + 'start' => 'The timestamp to start enumerating from. (1,2)', + 'end' => 'The timestamp to stop enumerating at. (1,2)', + 'dir' => 'The direction in which to enumerate. (1,2)', 'limit' => 'The maximum amount of revisions to list', - 'prop' => 'Which properties to get' + 'prop' => 'Which properties to get', + 'namespace' => 'Only list pages in this namespace (3)', + 'user' => 'Only list revisions by this user', + 'excludeuser' => 'Don\'t list revisions by this user', + 'from' => 'Start listing at this title (3)', + 'continue' => 'When more results are available, use this to continue (3)', + 'unique' => 'List only one revision for each page (3)', ); } public function getDescription() { - return 'List deleted revisions.'; + return array( 'List deleted revisions.', + 'This module operates in three modes:', + '1) List deleted revisions for the given title(s), sorted by timestamp', + '2) List deleted contributions for the given user, sorted by timestamp (no titles specified)', + '3) List all deleted revisions in the given namespace, sorted by title and timestamp (no titles specified, druser not set)', + 'Certain parameters only apply to some modes and are ignored in others.', + 'For instance, a parameter marked (1) only applies to mode 1 and is ignored in modes 2 and 3.', + ); } protected function getExamples() { return array ( - 'List the first 50 deleted revisions', + 'List the last deleted revisions of Main Page and Talk:Main Page, with content (mode 1):', + ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content', + 'List the last 50 deleted contributions by Bob (mode 2):', + ' api.php?action=query&list=deletedrevs&druser=Bob&drlimit=50', + 'List the first 50 deleted revisions in the main namespace (mode 3):', ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50', - 'List the last deleted revisions of Main Page and Talk:Main Page, with content:', - ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content' + 'List the first 50 deleted pages in the Talk namespace (mode 3):', + ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique', ); } public function getVersion() { - return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 40798 2008-09-13 20:41:58Z aaron $'; + return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 50220 2009-05-05 14:07:59Z tstarling $'; } -} +}
\ No newline at end of file |