Index: includes/api/ApiQuery.php =================================================================== --- includes/api/ApiQuery.php (revision 55711) +++ includes/api/ApiQuery.php (working copy) @@ -74,6 +74,7 @@ 'logevents' => 'ApiQueryLogEvents', 'recentchanges' => 'ApiQueryRecentChanges', 'search' => 'ApiQuerySearch', + 'tags' => 'ApiQueryTags', 'usercontribs' => 'ApiQueryContributions', 'watchlist' => 'ApiQueryWatchlist', 'watchlistraw' => 'ApiQueryWatchlistRaw', Index: includes/api/ApiQueryLogEvents.php =================================================================== --- includes/api/ApiQueryLogEvents.php (revision 55711) +++ includes/api/ApiQueryLogEvents.php (working copy) @@ -51,6 +51,7 @@ $this->fld_timestamp = in_array('timestamp', $prop); $this->fld_comment = in_array('comment', $prop); $this->fld_details = in_array('details', $prop); + $this->fld_tags = in_array('tags', $prop); list($tbl_logging, $tbl_page, $tbl_user) = $db->tableNamesN('logging', 'page', 'user'); @@ -85,6 +86,18 @@ $this->addFieldsIf('log_comment', $this->fld_comment); $this->addFieldsIf('log_params', $this->fld_details); + if($this->fld_tags) { + $this->addTables('tag_summary'); + $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', 'log_id=ts_log_id'))); + $this->addFields('ts_tags'); + } + + if( !is_null($params['tag']) ) { + $this->addTables('change_tag'); + $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('log_id=ct_log_id')))); + $this->addWhereFld('ct_tag' , $params['tag']); + } + if( !is_null($params['type']) ) { $this->addWhereFld('log_type', $params['type']); $index = 'type_time'; @@ -247,6 +260,16 @@ } } + if ($this->fld_tags) { + if ($row->ts_tags) { + $tags = explode(',', $row->ts_tags); + $this->getResult()->setIndexedTagName($tags, 'tag'); + $vals['tags'] = $tags; + } else { + $vals['tags'] = array(); + } + } + return $vals; } @@ -265,6 +288,7 @@ 'timestamp', 'comment', 'details', + 'tags' ) ), 'type' => array ( Index: includes/api/ApiQueryRecentChanges.php =================================================================== --- includes/api/ApiQueryRecentChanges.php (revision 55711) +++ includes/api/ApiQueryRecentChanges.php (working copy) @@ -174,6 +174,7 @@ $this->fld_redirect = isset($prop['redirect']); $this->fld_patrolled = isset($prop['patrolled']); $this->fld_loginfo = isset($prop['loginfo']); + $this->fld_tags = isset($prop['tags']); global $wgUser; if($this->fld_patrolled && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol()) @@ -203,6 +204,18 @@ $this->addFields('page_is_redirect'); } } + + if($this->fld_tags) { + $this->addTables('tag_summary'); + $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rc_id=ts_rc_id')))); + $this->addFields('ts_tags'); + } + + if(!is_null($params['tag'])) { + $this->addTables('change_tag'); + $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('rc_id=ct_rc_id')))); + $this->addWhereFld('ct_tag' , $params['tag']); + } $this->token = $params['token']; $this->addOption('LIMIT', $params['limit'] +1); $this->addOption('USE INDEX', array('recentchanges' => $index)); @@ -335,6 +348,16 @@ $row->rc_log_type, $row->rc_timestamp); } + if ($this->fld_tags) { + if ($row->ts_tags) { + $tags = explode(',', $row->ts_tags); + $this->getResult()->setIndexedTagName($tags, 'tag'); + $vals['tags'] = $tags; + } else { + $vals['tags'] = array(); + } + } + if(!is_null($this->token)) { $tokenFunctions = $this->getTokenFunctions(); @@ -408,6 +431,7 @@ 'redirect', 'patrolled', 'loginfo', + 'tags' ) ), 'token' => array( Index: includes/api/ApiQueryRevisions.php =================================================================== --- includes/api/ApiQueryRevisions.php (revision 55711) +++ includes/api/ApiQueryRevisions.php (working copy) @@ -42,7 +42,7 @@ } private $fld_ids = false, $fld_flags = false, $fld_timestamp = false, $fld_size = false, - $fld_comment = false, $fld_user = false, $fld_content = false; + $fld_comment = false, $fld_user = false, $fld_content = false, $fld_tags = false; protected function getTokenFunctions() { // tokenname => function @@ -121,9 +121,8 @@ } $db = $this->getDB(); - $this->addTables('revision'); + $this->addTables(array('page', 'revision')); $this->addFields(Revision::selectFields()); - $this->addTables('page'); $this->addWhere('page_id = rev_page'); $prop = array_flip($params['prop']); @@ -143,6 +142,19 @@ $this->addFields( Revision::selectPageFields() ); } + if (isset ($prop['tags'])) { + $this->fld_tags = true; + $this->addTables('tag_summary'); + $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rev_id=ts_rev_id')))); + $this->addFields('ts_tags'); + } + + if( !is_null($params['tag']) ) { + $this->addTables('change_tag'); + $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('rev_id=ct_rev_id')))); + $this->addWhereFld('ct_tag' , $params['tag']); + } + if (isset ($prop['content'])) { // For each page we will request, the user must have read rights for that page @@ -293,9 +305,9 @@ $this->setContinueEnumParameter('startid', intval($row->rev_id)); break; } - $revision = new Revision( $row ); + // - $fit = $this->addPageSubItem($revision->getPage(), $this->extractRowInfo($revision), 'rev'); + $fit = $this->addPageSubItem($row->rev_page, $this->extractRowInfo($row), 'rev'); if(!$fit) { if($enumRevMode) @@ -311,7 +323,8 @@ $db->freeResult($res); } - private function extractRowInfo( $revision ) { + private function extractRowInfo( $row ) { + $revision = new Revision( $row ); $title = $revision->getTitle(); $vals = array (); @@ -353,6 +366,16 @@ } } + if ($this->fld_tags) { + if ($row->ts_tags) { + $tags = explode(',', $row->ts_tags); + $this->getResult()->setIndexedTagName($tags, 'tag'); + $vals['tags'] = $tags; + } else { + $vals['tags'] = array(); + } + } + if(!is_null($this->token)) { $tokenFunctions = $this->getTokenFunctions(); @@ -427,6 +450,7 @@ 'size', 'comment', 'content', + 'tags' ) ), 'limit' => array ( Index: includes/api/ApiQueryTags.php =================================================================== --- includes/api/ApiQueryTags.php (revision 0) +++ includes/api/ApiQueryTags.php (revision 0) @@ -0,0 +1,177 @@ +extractRequestParams(); + + $prop = array_flip($params['prop']); + + $this->fld_displayname = isset($prop['displayname']); + $this->fld_description = isset($prop['description']); + $this->fld_hitcount = isset($prop['hitcount']); + + $this->limit = $params['limit']; + $this->result = $this->getResult(); + + $pageSet = $this->getPageSet(); + $titles = $pageSet->getTitles(); + $data = array(); + + $this->addTables('change_tag'); + $this->addFields('ct_tag'); + + if($this->fld_hitcount) + $this->addFields('count(*) AS hitcount'); + + $this->addOption('LIMIT', $this->limit + 1); + $this->addOption('GROUP BY', 'ct_tag'); + $this->addWhereRange('ct_tag', 'newer', $params['continue'], null); + + $res = $this->select(__METHOD__); + + $ok = true; + + while ( $row = $res->fetchObject() ) { + if(!$ok) break; + $ok = $this->doTag( $row->ct_tag, $row->hitcount ); + } + + //include tags with no hits yet + foreach( ChangeTags::listDefinedTags() as $tag ) { + if(!$ok) break; + $ok = $this->doTag( $tag, 0 ); + } + + $this->result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'tag'); + } + + private function doTag( $tagName, $hitcount ) { + static $count = 0; + static $doneTags = array(); + + if ( in_array( $tagName, $doneTags ) ) { + return true; + } + + if(++$count > $this->limit) + { + $this->setContinueEnumParameter('continue', $tagName); + return false; + } + + $tag = array(); + $tag['name'] = $tagName; + + if($this->fld_displayname) + $tag['displayname'] = ChangeTags::tagDescription( $tagName ); + + if($this->fld_description) + { + $msg = wfMsg( "tag-$tagName-description" ); + $msg = wfEmptyMsg( "tag-$tagName-description", $msg ) ? '' : $msg; + $tag['description'] = $msg; + } + + if($this->fld_hitcount) + $tag['hitcount'] = $hitcount; + + $doneTags[] = $tagName; + + $fit = $this->result->addValue(array('query', $this->getModuleName()), null, $tag); + if(!$fit) + { + $this->setContinueEnumParameter('continue', $tagName); + return false; + } + + return true; + } + + public function getAllowedParams() { + return array ( + 'continue' => array( + ), + 'limit' => array( + ApiBase :: PARAM_DFLT => 10, + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'prop' => array( + ApiBase :: PARAM_DFLT => 'name', + ApiBase :: PARAM_TYPE => array( + 'name', + 'displayname', + 'description', + 'hitcount' + ), + ApiBase :: PARAM_ISMULTI => true + ) + ); + } + + public function getParamDescription() { + return array ( + 'continue' => 'When more results are available, use this to continue', + 'limit' => 'The maximum number of tags to list', + 'prop' => 'Which properties to get', + ); + } + + public function getDescription() { + return 'List change tags.'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=tags&tgprop=displayname|description|hitcount' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryTags.php'; + } +} \ No newline at end of file Index: includes/api/ApiQueryUserContributions.php =================================================================== --- includes/api/ApiQueryUserContributions.php (revision 55711) +++ includes/api/ApiQueryUserContributions.php (working copy) @@ -42,7 +42,7 @@ private $params, $username; private $fld_ids = false, $fld_title = false, $fld_timestamp = false, $fld_comment = false, $fld_flags = false, - $fld_patrolled = false; + $fld_patrolled = false, $fld_tags = false; public function execute() { @@ -57,6 +57,7 @@ $this->fld_flags = isset($prop['flags']); $this->fld_timestamp = isset($prop['timestamp']); $this->fld_patrolled = isset($prop['patrolled']); + $this->fld_tags = isset($prop['tags']); // TODO: if the query is going only against the revision table, should this be done? $this->selectNamedDB('contributions', DB_SLAVE, 'contributions'); @@ -141,7 +142,7 @@ private function prepareQuery() { // We're after the revision table, and the corresponding page // row for anything we retrieve. We may also need the - // recentchanges row. + // recentchanges row and/or tag summary row. global $wgUser; $tables = array('page', 'revision'); // Order may change $this->addWhere('page_id=rev_page'); @@ -245,6 +246,19 @@ $this->addFieldsIf('rev_minor_edit', $this->fld_flags); $this->addFieldsIf('rev_parent_id', $this->fld_flags); $this->addFieldsIf('rc_patrolled', $this->fld_patrolled); + + if($this->fld_tags) + { + $this->addTables('tag_summary'); + $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rev_id=ts_rev_id')))); + $this->addFields('ts_tags'); + } + + if( !is_null($this->params['tag']) ) { + $this->addTables('change_tag'); + $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('rev_id=ct_rev_id')))); + $this->addWhereFld('ct_tag', $this->params['tag']); + } } /** @@ -292,6 +306,16 @@ if ($this->fld_size && !is_null($row->rev_len)) $vals['size'] = intval($row->rev_len); + if ($this->fld_tags) { + if ($row->ts_tags) { + $tags = explode(',', $row->ts_tags); + $this->getResult()->setIndexedTagName($tags, 'tag'); + $vals['tags'] = $tags; + } else { + $vals['tags'] = array(); + } + } + return $vals; } @@ -343,6 +367,7 @@ 'size', 'flags', 'patrolled', + 'tags' ) ), 'show' => array ( Index: includes/AutoLoader.php =================================================================== --- includes/AutoLoader.php (revision 55711) +++ includes/AutoLoader.php (working copy) @@ -307,6 +307,7 @@ 'ApiQueryRevisions' => 'includes/api/ApiQueryRevisions.php', 'ApiQuerySearch' => 'includes/api/ApiQuerySearch.php', 'ApiQuerySiteinfo' => 'includes/api/ApiQuerySiteinfo.php', + 'ApiQueryTags' => 'includes/api/ApiQueryTags.php', 'ApiQueryUserInfo' => 'includes/api/ApiQueryUserInfo.php', 'ApiQueryUsers' => 'includes/api/ApiQueryUsers.php', 'ApiQueryWatchlist' => 'includes/api/ApiQueryWatchlist.php',