ApiQueryLogEvents.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /*
  3. * Created on Oct 16, 2006
  4. *
  5. * API for MediaWiki 1.8+
  6. *
  7. * Copyright (C) 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, write to the Free Software Foundation, Inc.,
  21. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. * http://www.gnu.org/copyleft/gpl.html
  23. */
  24. if (!defined('MEDIAWIKI')) {
  25. // Eclipse helper - will be ignored in production
  26. require_once ('ApiQueryBase.php');
  27. }
  28. /**
  29. * Query action to List the log events, with optional filtering by various parameters.
  30. *
  31. * @ingroup API
  32. */
  33. class ApiQueryLogEvents extends ApiQueryBase {
  34. public function __construct($query, $moduleName) {
  35. parent :: __construct($query, $moduleName, 'le');
  36. }
  37. public function execute() {
  38. $params = $this->extractRequestParams();
  39. $db = $this->getDB();
  40. $prop = $params['prop'];
  41. $this->fld_ids = in_array('ids', $prop);
  42. $this->fld_title = in_array('title', $prop);
  43. $this->fld_type = in_array('type', $prop);
  44. $this->fld_user = in_array('user', $prop);
  45. $this->fld_timestamp = in_array('timestamp', $prop);
  46. $this->fld_comment = in_array('comment', $prop);
  47. $this->fld_details = in_array('details', $prop);
  48. list($tbl_logging, $tbl_page, $tbl_user) = $db->tableNamesN('logging', 'page', 'user');
  49. $hideLogs = LogEventsList::getExcludeClause($db);
  50. if($hideLogs !== false)
  51. $this->addWhere($hideLogs);
  52. // Order is significant here
  53. $this->addTables(array('logging', 'user', 'page'));
  54. $this->addOption('STRAIGHT_JOIN');
  55. $this->addJoinConds(array(
  56. 'user' => array('JOIN',
  57. 'user_id=log_user'),
  58. 'page' => array('LEFT JOIN',
  59. array( 'log_namespace=page_namespace',
  60. 'log_title=page_title'))));
  61. $index = 'times'; // default, may change
  62. $this->addFields(array (
  63. 'log_type',
  64. 'log_action',
  65. 'log_timestamp',
  66. 'log_deleted',
  67. ));
  68. $this->addFieldsIf('log_id', $this->fld_ids);
  69. $this->addFieldsIf('page_id', $this->fld_ids);
  70. $this->addFieldsIf('log_user', $this->fld_user);
  71. $this->addFieldsIf('user_name', $this->fld_user);
  72. $this->addFieldsIf('log_namespace', $this->fld_title);
  73. $this->addFieldsIf('log_title', $this->fld_title);
  74. $this->addFieldsIf('log_comment', $this->fld_comment);
  75. $this->addFieldsIf('log_params', $this->fld_details);
  76. if( !is_null($params['type']) ) {
  77. $this->addWhereFld('log_type', $params['type']);
  78. $index = 'type_time';
  79. }
  80. $this->addWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']);
  81. $limit = $params['limit'];
  82. $this->addOption('LIMIT', $limit +1);
  83. $user = $params['user'];
  84. if (!is_null($user)) {
  85. $userid = User::idFromName($user);
  86. if (!$userid)
  87. $this->dieUsage("User name $user not found", 'param_user');
  88. $this->addWhereFld('log_user', $userid);
  89. $index = 'user_time';
  90. }
  91. $title = $params['title'];
  92. if (!is_null($title)) {
  93. $titleObj = Title :: newFromText($title);
  94. if (is_null($titleObj))
  95. $this->dieUsage("Bad title value '$title'", 'param_title');
  96. $this->addWhereFld('log_namespace', $titleObj->getNamespace());
  97. $this->addWhereFld('log_title', $titleObj->getDBkey());
  98. // Use the title index in preference to the user index if there is a conflict
  99. $index = is_null($user) ? 'page_time' : array('page_time','user_time');
  100. }
  101. $this->addOption( 'USE INDEX', array( 'logging' => $index ) );
  102. // Paranoia: avoid brute force searches (bug 17342)
  103. if (!is_null($title)) {
  104. $this->addWhere('log_deleted & ' . LogPage::DELETED_ACTION . ' = 0');
  105. }
  106. if (!is_null($user)) {
  107. $this->addWhere('log_deleted & ' . LogPage::DELETED_USER . ' = 0');
  108. }
  109. $count = 0;
  110. $res = $this->select(__METHOD__);
  111. while ($row = $db->fetchObject($res)) {
  112. if (++ $count > $limit) {
  113. // We've reached the one extra which shows that there are additional pages to be had. Stop here...
  114. $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp));
  115. break;
  116. }
  117. $vals = $this->extractRowInfo($row);
  118. if(!$vals)
  119. continue;
  120. $fit = $this->getResult()->addValue(array('query', $this->getModuleName()), null, $vals);
  121. if(!$fit)
  122. {
  123. $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp));
  124. break;
  125. }
  126. }
  127. $db->freeResult($res);
  128. $this->getResult()->setIndexedTagName_internal(array('query', $this->getModuleName()), 'item');
  129. }
  130. public static function addLogParams($result, &$vals, $params, $type, $ts) {
  131. $params = explode("\n", $params);
  132. switch ($type) {
  133. case 'move':
  134. if (isset ($params[0])) {
  135. $title = Title :: newFromText($params[0]);
  136. if ($title) {
  137. $vals2 = array();
  138. ApiQueryBase :: addTitleInfo($vals2, $title, "new_");
  139. $vals[$type] = $vals2;
  140. }
  141. }
  142. if (isset ($params[1]) && $params[1]) {
  143. $vals[$type]['suppressedredirect'] = '';
  144. }
  145. $params = null;
  146. break;
  147. case 'patrol':
  148. $vals2 = array();
  149. list( $vals2['cur'], $vals2['prev'], $vals2['auto'] ) = $params;
  150. $vals[$type] = $vals2;
  151. $params = null;
  152. break;
  153. case 'rights':
  154. $vals2 = array();
  155. list( $vals2['old'], $vals2['new'] ) = $params;
  156. $vals[$type] = $vals2;
  157. $params = null;
  158. break;
  159. case 'block':
  160. $vals2 = array();
  161. list( $vals2['duration'], $vals2['flags'] ) = $params;
  162. $vals2['expiry'] = wfTimestamp(TS_ISO_8601,
  163. strtotime($params[0], wfTimestamp(TS_UNIX, $ts)));
  164. $vals[$type] = $vals2;
  165. $params = null;
  166. break;
  167. }
  168. if (!is_null($params)) {
  169. $result->setIndexedTagName($params, 'param');
  170. $vals = array_merge($vals, $params);
  171. }
  172. return $vals;
  173. }
  174. private function extractRowInfo($row) {
  175. $vals = array();
  176. if ($this->fld_ids) {
  177. $vals['logid'] = intval($row->log_id);
  178. $vals['pageid'] = intval($row->page_id);
  179. }
  180. if ($this->fld_title) {
  181. if (LogEventsList::isDeleted($row, LogPage::DELETED_ACTION)) {
  182. $vals['actionhidden'] = '';
  183. } else {
  184. $title = Title :: makeTitle($row->log_namespace, $row->log_title);
  185. ApiQueryBase :: addTitleInfo($vals, $title);
  186. }
  187. }
  188. if ($this->fld_type) {
  189. $vals['type'] = $row->log_type;
  190. $vals['action'] = $row->log_action;
  191. }
  192. if ($this->fld_details && $row->log_params !== '') {
  193. if (LogEventsList::isDeleted($row, LogPage::DELETED_ACTION)) {
  194. $vals['actionhidden'] = '';
  195. } else {
  196. self::addLogParams($this->getResult(), $vals,
  197. $row->log_params, $row->log_type,
  198. $row->log_timestamp);
  199. }
  200. }
  201. if ($this->fld_user) {
  202. if (LogEventsList::isDeleted($row, LogPage::DELETED_USER)) {
  203. $vals['userhidden'] = '';
  204. } else {
  205. $vals['user'] = $row->user_name;
  206. if(!$row->log_user)
  207. $vals['anon'] = '';
  208. }
  209. }
  210. if ($this->fld_timestamp) {
  211. $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->log_timestamp);
  212. }
  213. if ($this->fld_comment && isset($row->log_comment)) {
  214. if (LogEventsList::isDeleted($row, LogPage::DELETED_COMMENT)) {
  215. $vals['commenthidden'] = '';
  216. } else {
  217. $vals['comment'] = $row->log_comment;
  218. }
  219. }
  220. return $vals;
  221. }
  222. public function getAllowedParams() {
  223. global $wgLogTypes;
  224. return array (
  225. 'prop' => array (
  226. ApiBase :: PARAM_ISMULTI => true,
  227. ApiBase :: PARAM_DFLT => 'ids|title|type|user|timestamp|comment|details',
  228. ApiBase :: PARAM_TYPE => array (
  229. 'ids',
  230. 'title',
  231. 'type',
  232. 'user',
  233. 'timestamp',
  234. 'comment',
  235. 'details',
  236. )
  237. ),
  238. 'type' => array (
  239. ApiBase :: PARAM_TYPE => $wgLogTypes
  240. ),
  241. 'start' => array (
  242. ApiBase :: PARAM_TYPE => 'timestamp'
  243. ),
  244. 'end' => array (
  245. ApiBase :: PARAM_TYPE => 'timestamp'
  246. ),
  247. 'dir' => array (
  248. ApiBase :: PARAM_DFLT => 'older',
  249. ApiBase :: PARAM_TYPE => array (
  250. 'newer',
  251. 'older'
  252. )
  253. ),
  254. 'user' => null,
  255. 'title' => null,
  256. 'limit' => array (
  257. ApiBase :: PARAM_DFLT => 10,
  258. ApiBase :: PARAM_TYPE => 'limit',
  259. ApiBase :: PARAM_MIN => 1,
  260. ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
  261. ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
  262. )
  263. );
  264. }
  265. public function getParamDescription() {
  266. return array (
  267. 'prop' => 'Which properties to get',
  268. 'type' => 'Filter log entries to only this type(s)',
  269. 'start' => 'The timestamp to start enumerating from.',
  270. 'end' => 'The timestamp to end enumerating.',
  271. 'dir' => 'In which direction to enumerate.',
  272. 'user' => 'Filter entries to those made by the given user.',
  273. 'title' => 'Filter entries to those related to a page.',
  274. 'limit' => 'How many total event entries to return.'
  275. );
  276. }
  277. public function getDescription() {
  278. return 'Get events from logs.';
  279. }
  280. protected function getExamples() {
  281. return array (
  282. 'api.php?action=query&list=logevents'
  283. );
  284. }
  285. public function getVersion() {
  286. return __CLASS__ . ': $Id: ApiQueryLogEvents.php 47904 2009-03-01 11:02:49Z catrope $';
  287. }
  288. }