ApiQueryRecentChangesIntegrationTest.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. <?php
  2. use MediaWiki\Linker\LinkTarget;
  3. use MediaWiki\MediaWikiServices;
  4. /**
  5. * @group API
  6. * @group Database
  7. * @group medium
  8. *
  9. * @covers ApiQueryRecentChanges
  10. */
  11. class ApiQueryRecentChangesIntegrationTest extends ApiTestCase {
  12. public function __construct( $name = null, array $data = [], $dataName = '' ) {
  13. parent::__construct( $name, $data, $dataName );
  14. $this->tablesUsed[] = 'recentchanges';
  15. $this->tablesUsed[] = 'page';
  16. }
  17. protected function setUp() {
  18. parent::setUp();
  19. self::$users['ApiQueryRecentChangesIntegrationTestUser'] = $this->getMutableTestUser();
  20. wfGetDB( DB_MASTER )->delete( 'recentchanges', '*', __METHOD__ );
  21. }
  22. private function getLoggedInTestUser() {
  23. return self::$users['ApiQueryRecentChangesIntegrationTestUser']->getUser();
  24. }
  25. private function doPageEdit( User $user, LinkTarget $target, $summary ) {
  26. static $i = 0;
  27. $title = Title::newFromLinkTarget( $target );
  28. $page = WikiPage::factory( $title );
  29. $page->doEditContent(
  30. ContentHandler::makeContent( __CLASS__ . $i++, $title ),
  31. $summary,
  32. 0,
  33. false,
  34. $user
  35. );
  36. }
  37. private function doMinorPageEdit( User $user, LinkTarget $target, $summary ) {
  38. $title = Title::newFromLinkTarget( $target );
  39. $page = WikiPage::factory( $title );
  40. $page->doEditContent(
  41. ContentHandler::makeContent( __CLASS__, $title ),
  42. $summary,
  43. EDIT_MINOR,
  44. false,
  45. $user
  46. );
  47. }
  48. private function doBotPageEdit( User $user, LinkTarget $target, $summary ) {
  49. $title = Title::newFromLinkTarget( $target );
  50. $page = WikiPage::factory( $title );
  51. $page->doEditContent(
  52. ContentHandler::makeContent( __CLASS__, $title ),
  53. $summary,
  54. EDIT_FORCE_BOT,
  55. false,
  56. $user
  57. );
  58. }
  59. private function doAnonPageEdit( LinkTarget $target, $summary ) {
  60. $title = Title::newFromLinkTarget( $target );
  61. $page = WikiPage::factory( $title );
  62. $page->doEditContent(
  63. ContentHandler::makeContent( __CLASS__, $title ),
  64. $summary,
  65. 0,
  66. false,
  67. User::newFromId( 0 )
  68. );
  69. }
  70. private function deletePage( LinkTarget $target, $reason ) {
  71. $title = Title::newFromLinkTarget( $target );
  72. $page = WikiPage::factory( $title );
  73. $page->doDeleteArticleReal( $reason );
  74. }
  75. /**
  76. * Performs a batch of page edits as a specified user
  77. * @param User $user
  78. * @param array $editData associative array, keys:
  79. * - target => LinkTarget page to edit
  80. * - summary => string edit summary
  81. * - minorEdit => bool mark as minor edit if true (defaults to false)
  82. * - botEdit => bool mark as bot edit if true (defaults to false)
  83. */
  84. private function doPageEdits( User $user, array $editData ) {
  85. foreach ( $editData as $singleEditData ) {
  86. if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
  87. $this->doMinorPageEdit(
  88. $user,
  89. $singleEditData['target'],
  90. $singleEditData['summary']
  91. );
  92. continue;
  93. }
  94. if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
  95. $this->doBotPageEdit(
  96. $user,
  97. $singleEditData['target'],
  98. $singleEditData['summary']
  99. );
  100. continue;
  101. }
  102. $this->doPageEdit(
  103. $user,
  104. $singleEditData['target'],
  105. $singleEditData['summary']
  106. );
  107. }
  108. }
  109. private function doListRecentChangesRequest( array $params = [] ) {
  110. return $this->doApiRequest(
  111. array_merge(
  112. [ 'action' => 'query', 'list' => 'recentchanges' ],
  113. $params
  114. ),
  115. null,
  116. false,
  117. $this->getLoggedInTestUser()
  118. );
  119. }
  120. private function doGeneratorRecentChangesRequest( array $params = [] ) {
  121. return $this->doApiRequest(
  122. array_merge(
  123. [ 'action' => 'query', 'generator' => 'recentchanges' ],
  124. $params
  125. ),
  126. null,
  127. false,
  128. $this->getLoggedInTestUser()
  129. );
  130. }
  131. private function getItemsFromApiResponse( array $response ) {
  132. return $response[0]['query']['recentchanges'];
  133. }
  134. private function getTitleFormatter() {
  135. return new MediaWikiTitleCodec(
  136. Language::factory( 'en' ),
  137. MediaWikiServices::getInstance()->getGenderCache()
  138. );
  139. }
  140. private function getPrefixedText( LinkTarget $target ) {
  141. $formatter = $this->getTitleFormatter();
  142. return $formatter->getPrefixedText( $target );
  143. }
  144. public function testListRecentChanges_returnsRCInfo() {
  145. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  146. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  147. $result = $this->doListRecentChangesRequest();
  148. $this->assertArrayHasKey( 'query', $result[0] );
  149. $this->assertArrayHasKey( 'recentchanges', $result[0]['query'] );
  150. $items = $this->getItemsFromApiResponse( $result );
  151. $this->assertCount( 1, $items );
  152. $item = $items[0];
  153. $this->assertArraySubset(
  154. [
  155. 'type' => 'new',
  156. 'ns' => $target->getNamespace(),
  157. 'title' => $this->getPrefixedText( $target ),
  158. ],
  159. $item
  160. );
  161. $this->assertArrayNotHasKey( 'bot', $item );
  162. $this->assertArrayNotHasKey( 'new', $item );
  163. $this->assertArrayNotHasKey( 'minor', $item );
  164. $this->assertArrayHasKey( 'pageid', $item );
  165. $this->assertArrayHasKey( 'revid', $item );
  166. $this->assertArrayHasKey( 'old_revid', $item );
  167. }
  168. public function testIdsPropParameter() {
  169. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  170. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  171. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'ids', ] );
  172. $items = $this->getItemsFromApiResponse( $result );
  173. $this->assertCount( 1, $items );
  174. $this->assertArrayHasKey( 'pageid', $items[0] );
  175. $this->assertArrayHasKey( 'revid', $items[0] );
  176. $this->assertArrayHasKey( 'old_revid', $items[0] );
  177. $this->assertEquals( 'new', $items[0]['type'] );
  178. }
  179. public function testTitlePropParameter() {
  180. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  181. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  182. $this->doPageEdits(
  183. $this->getLoggedInTestUser(),
  184. [
  185. [
  186. 'target' => $subjectTarget,
  187. 'summary' => 'Create the page',
  188. ],
  189. [
  190. 'target' => $talkTarget,
  191. 'summary' => 'Create Talk page',
  192. ],
  193. ]
  194. );
  195. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', ] );
  196. $this->assertEquals(
  197. [
  198. [
  199. 'type' => 'new',
  200. 'ns' => $talkTarget->getNamespace(),
  201. 'title' => $this->getPrefixedText( $talkTarget ),
  202. ],
  203. [
  204. 'type' => 'new',
  205. 'ns' => $subjectTarget->getNamespace(),
  206. 'title' => $this->getPrefixedText( $subjectTarget ),
  207. ],
  208. ],
  209. $this->getItemsFromApiResponse( $result )
  210. );
  211. }
  212. public function testFlagsPropParameter() {
  213. $normalEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  214. $minorEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageM' );
  215. $botEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageB' );
  216. $this->doPageEdits(
  217. $this->getLoggedInTestUser(),
  218. [
  219. [
  220. 'target' => $normalEditTarget,
  221. 'summary' => 'Create the page',
  222. ],
  223. [
  224. 'target' => $minorEditTarget,
  225. 'summary' => 'Create the page',
  226. ],
  227. [
  228. 'target' => $minorEditTarget,
  229. 'summary' => 'Change content',
  230. 'minorEdit' => true,
  231. ],
  232. [
  233. 'target' => $botEditTarget,
  234. 'summary' => 'Create the page with a bot',
  235. 'botEdit' => true,
  236. ],
  237. ]
  238. );
  239. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'flags', ] );
  240. $this->assertEquals(
  241. [
  242. [
  243. 'type' => 'new',
  244. 'new' => true,
  245. 'minor' => false,
  246. 'bot' => true,
  247. ],
  248. [
  249. 'type' => 'edit',
  250. 'new' => false,
  251. 'minor' => true,
  252. 'bot' => false,
  253. ],
  254. [
  255. 'type' => 'new',
  256. 'new' => true,
  257. 'minor' => false,
  258. 'bot' => false,
  259. ],
  260. [
  261. 'type' => 'new',
  262. 'new' => true,
  263. 'minor' => false,
  264. 'bot' => false,
  265. ],
  266. ],
  267. $this->getItemsFromApiResponse( $result )
  268. );
  269. }
  270. public function testUserPropParameter() {
  271. $userEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  272. $anonEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageA' );
  273. $this->doPageEdit( $this->getLoggedInTestUser(), $userEditTarget, 'Create the page' );
  274. $this->doAnonPageEdit( $anonEditTarget, 'Create the page' );
  275. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'user', ] );
  276. $this->assertEquals(
  277. [
  278. [
  279. 'type' => 'new',
  280. 'anon' => true,
  281. 'user' => User::newFromId( 0 )->getName(),
  282. ],
  283. [
  284. 'type' => 'new',
  285. 'user' => $this->getLoggedInTestUser()->getName(),
  286. ],
  287. ],
  288. $this->getItemsFromApiResponse( $result )
  289. );
  290. }
  291. public function testUserIdPropParameter() {
  292. $user = $this->getLoggedInTestUser();
  293. $userEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  294. $anonEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageA' );
  295. $this->doPageEdit( $user, $userEditTarget, 'Create the page' );
  296. $this->doAnonPageEdit( $anonEditTarget, 'Create the page' );
  297. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'userid', ] );
  298. $this->assertEquals(
  299. [
  300. [
  301. 'type' => 'new',
  302. 'anon' => true,
  303. 'userid' => 0,
  304. ],
  305. [
  306. 'type' => 'new',
  307. 'userid' => $user->getId(),
  308. ],
  309. ],
  310. $this->getItemsFromApiResponse( $result )
  311. );
  312. }
  313. public function testCommentPropParameter() {
  314. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  315. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the <b>page</b>' );
  316. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'comment', ] );
  317. $this->assertEquals(
  318. [
  319. [
  320. 'type' => 'new',
  321. 'comment' => 'Create the <b>page</b>',
  322. ],
  323. ],
  324. $this->getItemsFromApiResponse( $result )
  325. );
  326. }
  327. public function testParsedCommentPropParameter() {
  328. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  329. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the <b>page</b>' );
  330. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'parsedcomment', ] );
  331. $this->assertEquals(
  332. [
  333. [
  334. 'type' => 'new',
  335. 'parsedcomment' => 'Create the &lt;b&gt;page&lt;/b&gt;',
  336. ],
  337. ],
  338. $this->getItemsFromApiResponse( $result )
  339. );
  340. }
  341. public function testTimestampPropParameter() {
  342. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  343. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  344. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'timestamp', ] );
  345. $items = $this->getItemsFromApiResponse( $result );
  346. $this->assertCount( 1, $items );
  347. $this->assertArrayHasKey( 'timestamp', $items[0] );
  348. $this->assertInternalType( 'string', $items[0]['timestamp'] );
  349. }
  350. public function testSizesPropParameter() {
  351. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  352. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  353. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'sizes', ] );
  354. $this->assertEquals(
  355. [
  356. [
  357. 'type' => 'new',
  358. 'oldlen' => 0,
  359. 'newlen' => 38,
  360. ],
  361. ],
  362. $this->getItemsFromApiResponse( $result )
  363. );
  364. }
  365. private function createPageAndDeleteIt( LinkTarget $target ) {
  366. $this->doPageEdit( $this->getLoggedInTestUser(),
  367. $target,
  368. 'Create the page that will be deleted'
  369. );
  370. $this->deletePage( $target, 'Important Reason' );
  371. }
  372. public function testLoginfoPropParameter() {
  373. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  374. $this->createPageAndDeleteIt( $target );
  375. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'loginfo', ] );
  376. $items = $this->getItemsFromApiResponse( $result );
  377. $this->assertCount( 1, $items );
  378. $this->assertArraySubset(
  379. [
  380. 'type' => 'log',
  381. 'logtype' => 'delete',
  382. 'logaction' => 'delete',
  383. 'logparams' => [],
  384. ],
  385. $items[0]
  386. );
  387. $this->assertArrayHasKey( 'logid', $items[0] );
  388. }
  389. public function testEmptyPropParameter() {
  390. $user = $this->getLoggedInTestUser();
  391. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  392. $this->doPageEdit( $user, $target, 'Create the page' );
  393. $result = $this->doListRecentChangesRequest( [ 'rcprop' => '', ] );
  394. $this->assertEquals(
  395. [
  396. [
  397. 'type' => 'new',
  398. ]
  399. ],
  400. $this->getItemsFromApiResponse( $result )
  401. );
  402. }
  403. public function testNamespaceParam() {
  404. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  405. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  406. $this->doPageEdits(
  407. $this->getLoggedInTestUser(),
  408. [
  409. [
  410. 'target' => $subjectTarget,
  411. 'summary' => 'Create the page',
  412. ],
  413. [
  414. 'target' => $talkTarget,
  415. 'summary' => 'Create the talk page',
  416. ],
  417. ]
  418. );
  419. $result = $this->doListRecentChangesRequest( [ 'rcnamespace' => '0', ] );
  420. $items = $this->getItemsFromApiResponse( $result );
  421. $this->assertCount( 1, $items );
  422. $this->assertArraySubset(
  423. [
  424. 'ns' => 0,
  425. 'title' => $this->getPrefixedText( $subjectTarget ),
  426. ],
  427. $items[0]
  428. );
  429. }
  430. public function testShowAnonParams() {
  431. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  432. $this->doAnonPageEdit( $target, 'Create the page' );
  433. $resultAnon = $this->doListRecentChangesRequest( [
  434. 'rcprop' => 'user',
  435. 'rcshow' => WatchedItemQueryService::FILTER_ANON
  436. ] );
  437. $resultNotAnon = $this->doListRecentChangesRequest( [
  438. 'rcprop' => 'user',
  439. 'rcshow' => WatchedItemQueryService::FILTER_NOT_ANON
  440. ] );
  441. $items = $this->getItemsFromApiResponse( $resultAnon );
  442. $this->assertCount( 1, $items );
  443. $this->assertArraySubset( [ 'anon' => true ], $items[0] );
  444. $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotAnon ) );
  445. }
  446. public function testNewAndEditTypeParameters() {
  447. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  448. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  449. $this->doPageEdits(
  450. $this->getLoggedInTestUser(),
  451. [
  452. [
  453. 'target' => $subjectTarget,
  454. 'summary' => 'Create the page',
  455. ],
  456. [
  457. 'target' => $subjectTarget,
  458. 'summary' => 'Change the content',
  459. ],
  460. [
  461. 'target' => $talkTarget,
  462. 'summary' => 'Create Talk page',
  463. ],
  464. ]
  465. );
  466. $resultNew = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'new' ] );
  467. $resultEdit = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'edit' ] );
  468. $this->assertEquals(
  469. [
  470. [
  471. 'type' => 'new',
  472. 'ns' => $talkTarget->getNamespace(),
  473. 'title' => $this->getPrefixedText( $talkTarget ),
  474. ],
  475. [
  476. 'type' => 'new',
  477. 'ns' => $subjectTarget->getNamespace(),
  478. 'title' => $this->getPrefixedText( $subjectTarget ),
  479. ],
  480. ],
  481. $this->getItemsFromApiResponse( $resultNew )
  482. );
  483. $this->assertEquals(
  484. [
  485. [
  486. 'type' => 'edit',
  487. 'ns' => $subjectTarget->getNamespace(),
  488. 'title' => $this->getPrefixedText( $subjectTarget ),
  489. ],
  490. ],
  491. $this->getItemsFromApiResponse( $resultEdit )
  492. );
  493. }
  494. public function testLogTypeParameters() {
  495. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  496. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  497. $this->createPageAndDeleteIt( $subjectTarget );
  498. $this->doPageEdit( $this->getLoggedInTestUser(), $talkTarget, 'Create Talk page' );
  499. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'log' ] );
  500. $this->assertEquals(
  501. [
  502. [
  503. 'type' => 'log',
  504. 'ns' => $subjectTarget->getNamespace(),
  505. 'title' => $this->getPrefixedText( $subjectTarget ),
  506. ],
  507. ],
  508. $this->getItemsFromApiResponse( $result )
  509. );
  510. }
  511. private function getExternalRC( LinkTarget $target ) {
  512. $title = Title::newFromLinkTarget( $target );
  513. $rc = new RecentChange;
  514. $rc->mTitle = $title;
  515. $rc->mAttribs = [
  516. 'rc_timestamp' => wfTimestamp( TS_MW ),
  517. 'rc_namespace' => $title->getNamespace(),
  518. 'rc_title' => $title->getDBkey(),
  519. 'rc_type' => RC_EXTERNAL,
  520. 'rc_source' => 'foo',
  521. 'rc_minor' => 0,
  522. 'rc_cur_id' => $title->getArticleID(),
  523. 'rc_user' => 0,
  524. 'rc_user_text' => 'm>External User',
  525. 'rc_comment' => '',
  526. 'rc_comment_text' => '',
  527. 'rc_comment_data' => null,
  528. 'rc_this_oldid' => $title->getLatestRevID(),
  529. 'rc_last_oldid' => $title->getLatestRevID(),
  530. 'rc_bot' => 0,
  531. 'rc_ip' => '',
  532. 'rc_patrolled' => 0,
  533. 'rc_new' => 0,
  534. 'rc_old_len' => $title->getLength(),
  535. 'rc_new_len' => $title->getLength(),
  536. 'rc_deleted' => 0,
  537. 'rc_logid' => 0,
  538. 'rc_log_type' => null,
  539. 'rc_log_action' => '',
  540. 'rc_params' => '',
  541. ];
  542. $rc->mExtra = [
  543. 'prefixedDBkey' => $title->getPrefixedDBkey(),
  544. 'lastTimestamp' => 0,
  545. 'oldSize' => $title->getLength(),
  546. 'newSize' => $title->getLength(),
  547. 'pageStatus' => 'changed'
  548. ];
  549. return $rc;
  550. }
  551. public function testExternalTypeParameters() {
  552. $user = $this->getLoggedInTestUser();
  553. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  554. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  555. $this->doPageEdit( $user, $subjectTarget, 'Create the page' );
  556. $this->doPageEdit( $user, $talkTarget, 'Create Talk page' );
  557. $rc = $this->getExternalRC( $subjectTarget );
  558. $rc->save();
  559. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'external' ] );
  560. $this->assertEquals(
  561. [
  562. [
  563. 'type' => 'external',
  564. 'ns' => $subjectTarget->getNamespace(),
  565. 'title' => $this->getPrefixedText( $subjectTarget ),
  566. ],
  567. ],
  568. $this->getItemsFromApiResponse( $result )
  569. );
  570. }
  571. public function testCategorizeTypeParameter() {
  572. $user = $this->getLoggedInTestUser();
  573. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  574. $categoryTarget = new TitleValue( NS_CATEGORY, 'ApiQueryRecentChangesIntegrationTestCategory' );
  575. $this->doPageEdits(
  576. $user,
  577. [
  578. [
  579. 'target' => $categoryTarget,
  580. 'summary' => 'Create the category',
  581. ],
  582. [
  583. 'target' => $subjectTarget,
  584. 'summary' => 'Create the page and add it to the category',
  585. ],
  586. ]
  587. );
  588. $title = Title::newFromLinkTarget( $subjectTarget );
  589. $revision = Revision::newFromTitle( $title );
  590. $rc = RecentChange::newForCategorization(
  591. $revision->getTimestamp(),
  592. Title::newFromLinkTarget( $categoryTarget ),
  593. $user,
  594. $revision->getComment(),
  595. $title,
  596. 0,
  597. $revision->getId(),
  598. null,
  599. false
  600. );
  601. $rc->save();
  602. $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'categorize' ] );
  603. $this->assertEquals(
  604. [
  605. [
  606. 'type' => 'categorize',
  607. 'ns' => $categoryTarget->getNamespace(),
  608. 'title' => $this->getPrefixedText( $categoryTarget ),
  609. ],
  610. ],
  611. $this->getItemsFromApiResponse( $result )
  612. );
  613. }
  614. public function testLimitParam() {
  615. $target1 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  616. $target2 = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  617. $target3 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage2' );
  618. $this->doPageEdits(
  619. $this->getLoggedInTestUser(),
  620. [
  621. [
  622. 'target' => $target1,
  623. 'summary' => 'Create the page',
  624. ],
  625. [
  626. 'target' => $target2,
  627. 'summary' => 'Create Talk page',
  628. ],
  629. [
  630. 'target' => $target3,
  631. 'summary' => 'Create the page',
  632. ],
  633. ]
  634. );
  635. $resultWithoutLimit = $this->doListRecentChangesRequest( [ 'rcprop' => 'title' ] );
  636. $resultWithLimit = $this->doListRecentChangesRequest( [ 'rclimit' => 2, 'rcprop' => 'title' ] );
  637. $this->assertEquals(
  638. [
  639. [
  640. 'type' => 'new',
  641. 'ns' => $target3->getNamespace(),
  642. 'title' => $this->getPrefixedText( $target3 )
  643. ],
  644. [
  645. 'type' => 'new',
  646. 'ns' => $target2->getNamespace(),
  647. 'title' => $this->getPrefixedText( $target2 )
  648. ],
  649. [
  650. 'type' => 'new',
  651. 'ns' => $target1->getNamespace(),
  652. 'title' => $this->getPrefixedText( $target1 )
  653. ],
  654. ],
  655. $this->getItemsFromApiResponse( $resultWithoutLimit )
  656. );
  657. $this->assertEquals(
  658. [
  659. [
  660. 'type' => 'new',
  661. 'ns' => $target3->getNamespace(),
  662. 'title' => $this->getPrefixedText( $target3 )
  663. ],
  664. [
  665. 'type' => 'new',
  666. 'ns' => $target2->getNamespace(),
  667. 'title' => $this->getPrefixedText( $target2 )
  668. ],
  669. ],
  670. $this->getItemsFromApiResponse( $resultWithLimit )
  671. );
  672. $this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
  673. $this->assertArrayHasKey( 'rccontinue', $resultWithLimit[0]['continue'] );
  674. }
  675. public function testAllRevParam() {
  676. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  677. $this->doPageEdits(
  678. $this->getLoggedInTestUser(),
  679. [
  680. [
  681. 'target' => $target,
  682. 'summary' => 'Create the page',
  683. ],
  684. [
  685. 'target' => $target,
  686. 'summary' => 'Change the content',
  687. ],
  688. ]
  689. );
  690. $resultAllRev = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rcallrev' => '', ] );
  691. $resultNoAllRev = $this->doListRecentChangesRequest( [ 'rcprop' => 'title' ] );
  692. $this->assertEquals(
  693. [
  694. [
  695. 'type' => 'edit',
  696. 'ns' => $target->getNamespace(),
  697. 'title' => $this->getPrefixedText( $target ),
  698. ],
  699. [
  700. 'type' => 'new',
  701. 'ns' => $target->getNamespace(),
  702. 'title' => $this->getPrefixedText( $target ),
  703. ],
  704. ],
  705. $this->getItemsFromApiResponse( $resultNoAllRev )
  706. );
  707. $this->assertEquals(
  708. [
  709. [
  710. 'type' => 'edit',
  711. 'ns' => $target->getNamespace(),
  712. 'title' => $this->getPrefixedText( $target ),
  713. ],
  714. [
  715. 'type' => 'new',
  716. 'ns' => $target->getNamespace(),
  717. 'title' => $this->getPrefixedText( $target ),
  718. ],
  719. ],
  720. $this->getItemsFromApiResponse( $resultAllRev )
  721. );
  722. }
  723. public function testDirParams() {
  724. $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  725. $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  726. $this->doPageEdits(
  727. $this->getLoggedInTestUser(),
  728. [
  729. [
  730. 'target' => $subjectTarget,
  731. 'summary' => 'Create the page',
  732. ],
  733. [
  734. 'target' => $talkTarget,
  735. 'summary' => 'Create Talk page',
  736. ],
  737. ]
  738. );
  739. $resultDirOlder = $this->doListRecentChangesRequest(
  740. [ 'rcdir' => 'older', 'rcprop' => 'title' ]
  741. );
  742. $resultDirNewer = $this->doListRecentChangesRequest(
  743. [ 'rcdir' => 'newer', 'rcprop' => 'title' ]
  744. );
  745. $this->assertEquals(
  746. [
  747. [
  748. 'type' => 'new',
  749. 'ns' => $talkTarget->getNamespace(),
  750. 'title' => $this->getPrefixedText( $talkTarget )
  751. ],
  752. [
  753. 'type' => 'new',
  754. 'ns' => $subjectTarget->getNamespace(),
  755. 'title' => $this->getPrefixedText( $subjectTarget )
  756. ],
  757. ],
  758. $this->getItemsFromApiResponse( $resultDirOlder )
  759. );
  760. $this->assertEquals(
  761. [
  762. [
  763. 'type' => 'new',
  764. 'ns' => $subjectTarget->getNamespace(),
  765. 'title' => $this->getPrefixedText( $subjectTarget )
  766. ],
  767. [
  768. 'type' => 'new',
  769. 'ns' => $talkTarget->getNamespace(),
  770. 'title' => $this->getPrefixedText( $talkTarget )
  771. ],
  772. ],
  773. $this->getItemsFromApiResponse( $resultDirNewer )
  774. );
  775. }
  776. public function testTitleParams() {
  777. $page1 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  778. $page2 = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage2' );
  779. $page3 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage3' );
  780. $this->doPageEdits(
  781. $this->getLoggedInTestUser(),
  782. [
  783. [
  784. 'target' => $page1,
  785. 'summary' => 'Create the page',
  786. ],
  787. [
  788. 'target' => $page2,
  789. 'summary' => 'Create the page',
  790. ],
  791. [
  792. 'target' => $page3,
  793. 'summary' => 'Create the page',
  794. ],
  795. ]
  796. );
  797. $result = $this->doListRecentChangesRequest(
  798. [
  799. 'rctitle' => 'ApiQueryRecentChangesIntegrationTestPage',
  800. 'rcprop' => 'title'
  801. ]
  802. );
  803. $result2 = $this->doListRecentChangesRequest(
  804. [
  805. 'rctitle' => 'Talk:ApiQueryRecentChangesIntegrationTestPage2',
  806. 'rcprop' => 'title'
  807. ]
  808. );
  809. $this->assertEquals(
  810. [
  811. [
  812. 'type' => 'new',
  813. 'ns' => $page1->getNamespace(),
  814. 'title' => $this->getPrefixedText( $page1 )
  815. ],
  816. ],
  817. $this->getItemsFromApiResponse( $result )
  818. );
  819. $this->assertEquals(
  820. [
  821. [
  822. 'type' => 'new',
  823. 'ns' => $page2->getNamespace(),
  824. 'title' => $this->getPrefixedText( $page2 )
  825. ],
  826. ],
  827. $this->getItemsFromApiResponse( $result2 )
  828. );
  829. }
  830. public function testStartEndParams() {
  831. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  832. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  833. $resultStart = $this->doListRecentChangesRequest( [
  834. 'rcstart' => '20010115000000',
  835. 'rcdir' => 'newer',
  836. 'rcprop' => 'title',
  837. ] );
  838. $resultEnd = $this->doListRecentChangesRequest( [
  839. 'rcend' => '20010115000000',
  840. 'rcdir' => 'newer',
  841. 'rcprop' => 'title',
  842. ] );
  843. $this->assertEquals(
  844. [
  845. [
  846. 'type' => 'new',
  847. 'ns' => $target->getNamespace(),
  848. 'title' => $this->getPrefixedText( $target ),
  849. ]
  850. ],
  851. $this->getItemsFromApiResponse( $resultStart )
  852. );
  853. $this->assertEmpty( $this->getItemsFromApiResponse( $resultEnd ) );
  854. }
  855. public function testContinueParam() {
  856. $target1 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  857. $target2 = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
  858. $target3 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage2' );
  859. $this->doPageEdits(
  860. $this->getLoggedInTestUser(),
  861. [
  862. [
  863. 'target' => $target1,
  864. 'summary' => 'Create the page',
  865. ],
  866. [
  867. 'target' => $target2,
  868. 'summary' => 'Create Talk page',
  869. ],
  870. [
  871. 'target' => $target3,
  872. 'summary' => 'Create the page',
  873. ],
  874. ]
  875. );
  876. $firstResult = $this->doListRecentChangesRequest( [ 'rclimit' => 2, 'rcprop' => 'title' ] );
  877. $this->assertArrayHasKey( 'continue', $firstResult[0] );
  878. $this->assertArrayHasKey( 'rccontinue', $firstResult[0]['continue'] );
  879. $continuationParam = $firstResult[0]['continue']['rccontinue'];
  880. $continuedResult = $this->doListRecentChangesRequest(
  881. [ 'rccontinue' => $continuationParam, 'rcprop' => 'title' ]
  882. );
  883. $this->assertEquals(
  884. [
  885. [
  886. 'type' => 'new',
  887. 'ns' => $target3->getNamespace(),
  888. 'title' => $this->getPrefixedText( $target3 ),
  889. ],
  890. [
  891. 'type' => 'new',
  892. 'ns' => $target2->getNamespace(),
  893. 'title' => $this->getPrefixedText( $target2 ),
  894. ],
  895. ],
  896. $this->getItemsFromApiResponse( $firstResult )
  897. );
  898. $this->assertEquals(
  899. [
  900. [
  901. 'type' => 'new',
  902. 'ns' => $target1->getNamespace(),
  903. 'title' => $this->getPrefixedText( $target1 )
  904. ]
  905. ],
  906. $this->getItemsFromApiResponse( $continuedResult )
  907. );
  908. }
  909. public function testGeneratorRecentChangesPropInfo_returnsRCPages() {
  910. $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
  911. $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
  912. $result = $this->doGeneratorRecentChangesRequest( [ 'prop' => 'info' ] );
  913. $this->assertArrayHasKey( 'query', $result[0] );
  914. $this->assertArrayHasKey( 'pages', $result[0]['query'] );
  915. // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
  916. $pages = array_values( $result[0]['query']['pages'] );
  917. $this->assertCount( 1, $pages );
  918. $this->assertArraySubset(
  919. [
  920. 'ns' => $target->getNamespace(),
  921. 'title' => $this->getPrefixedText( $target ),
  922. 'new' => true,
  923. ],
  924. $pages[0]
  925. );
  926. }
  927. }