MediaWiki  master
UserTest.php
Go to the documentation of this file.
1 <?php
2 
3 define( 'NS_UNITTEST', 5600 );
4 define( 'NS_UNITTEST_TALK', 5601 );
5 
11 
15 class UserTest extends MediaWikiTestCase {
16 
18  const USER_TALK_PAGE = '<user talk page>';
19 
23  protected $user;
24 
25  protected function setUp() {
26  parent::setUp();
27 
28  $this->setMwGlobals( [
29  'wgGroupPermissions' => [],
30  'wgRevokePermissions' => [],
31  'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
32  ] );
33  $this->overrideMwServices();
34 
35  $this->setUpPermissionGlobals();
36 
37  $this->user = $this->getTestUser( [ 'unittesters' ] )->getUser();
38  }
39 
40  private function setUpPermissionGlobals() {
42 
43  # Data for regular $wgGroupPermissions test
44  $wgGroupPermissions['unittesters'] = [
45  'test' => true,
46  'runtest' => true,
47  'writetest' => false,
48  'nukeworld' => false,
49  ];
50  $wgGroupPermissions['testwriters'] = [
51  'test' => true,
52  'writetest' => true,
53  'modifytest' => true,
54  ];
55 
56  # Data for regular $wgRevokePermissions test
57  $wgRevokePermissions['formertesters'] = [
58  'runtest' => true,
59  ];
60 
61  # For the options test
62  $wgGroupPermissions['*'] = [
63  'editmyoptions' => true,
64  ];
65  }
66 
70  public function testGroupPermissions() {
71  $rights = User::getGroupPermissions( [ 'unittesters' ] );
72  $this->assertContains( 'runtest', $rights );
73  $this->assertNotContains( 'writetest', $rights );
74  $this->assertNotContains( 'modifytest', $rights );
75  $this->assertNotContains( 'nukeworld', $rights );
76 
77  $rights = User::getGroupPermissions( [ 'unittesters', 'testwriters' ] );
78  $this->assertContains( 'runtest', $rights );
79  $this->assertContains( 'writetest', $rights );
80  $this->assertContains( 'modifytest', $rights );
81  $this->assertNotContains( 'nukeworld', $rights );
82  }
83 
87  public function testRevokePermissions() {
88  $rights = User::getGroupPermissions( [ 'unittesters', 'formertesters' ] );
89  $this->assertNotContains( 'runtest', $rights );
90  $this->assertNotContains( 'writetest', $rights );
91  $this->assertNotContains( 'modifytest', $rights );
92  $this->assertNotContains( 'nukeworld', $rights );
93  }
94 
98  public function testUserPermissions() {
99  $rights = $this->user->getRights();
100  $this->assertContains( 'runtest', $rights );
101  $this->assertNotContains( 'writetest', $rights );
102  $this->assertNotContains( 'modifytest', $rights );
103  $this->assertNotContains( 'nukeworld', $rights );
104  }
105 
109  public function testUserGetRightsHooks() {
110  $user = $this->getTestUser( [ 'unittesters', 'testwriters' ] )->getUser();
111  $userWrapper = TestingAccessWrapper::newFromObject( $user );
112 
113  $rights = $user->getRights();
114  $this->assertContains( 'test', $rights, 'sanity check' );
115  $this->assertContains( 'runtest', $rights, 'sanity check' );
116  $this->assertContains( 'writetest', $rights, 'sanity check' );
117  $this->assertNotContains( 'nukeworld', $rights, 'sanity check' );
118 
119  // Add a hook manipluating the rights
120  $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'UserGetRights' => [ function ( $user, &$rights ) {
121  $rights[] = 'nukeworld';
122  $rights = array_diff( $rights, [ 'writetest' ] );
123  } ] ] );
124 
125  $userWrapper->mRights = null;
126  $rights = $user->getRights();
127  $this->assertContains( 'test', $rights );
128  $this->assertContains( 'runtest', $rights );
129  $this->assertNotContains( 'writetest', $rights );
130  $this->assertContains( 'nukeworld', $rights );
131 
132  // Add a Session that limits rights
133  $mock = $this->getMockBuilder( stdClass::class )
134  ->setMethods( [ 'getAllowedUserRights', 'deregisterSession', 'getSessionId' ] )
135  ->getMock();
136  $mock->method( 'getAllowedUserRights' )->willReturn( [ 'test', 'writetest' ] );
137  $mock->method( 'getSessionId' )->willReturn(
138  new MediaWiki\Session\SessionId( str_repeat( 'X', 32 ) )
139  );
141  $mockRequest = $this->getMockBuilder( FauxRequest::class )
142  ->setMethods( [ 'getSession' ] )
143  ->getMock();
144  $mockRequest->method( 'getSession' )->willReturn( $session );
145  $userWrapper->mRequest = $mockRequest;
146 
147  $userWrapper->mRights = null;
148  $rights = $user->getRights();
149  $this->assertContains( 'test', $rights );
150  $this->assertNotContains( 'runtest', $rights );
151  $this->assertNotContains( 'writetest', $rights );
152  $this->assertNotContains( 'nukeworld', $rights );
153  }
154 
159  public function testGetGroupsWithPermission( $expected, $right ) {
161  sort( $result );
162  sort( $expected );
163 
164  $this->assertEquals( $expected, $result, "Groups with permission $right" );
165  }
166 
167  public static function provideGetGroupsWithPermission() {
168  return [
169  [
170  [ 'unittesters', 'testwriters' ],
171  'test'
172  ],
173  [
174  [ 'unittesters' ],
175  'runtest'
176  ],
177  [
178  [ 'testwriters' ],
179  'writetest'
180  ],
181  [
182  [ 'testwriters' ],
183  'modifytest'
184  ],
185  ];
186  }
187 
192  public function testIsIP( $value, $result, $message ) {
193  $this->assertEquals( $this->user->isIP( $value ), $result, $message );
194  }
195 
196  public static function provideIPs() {
197  return [
198  [ '', false, 'Empty string' ],
199  [ ' ', false, 'Blank space' ],
200  [ '10.0.0.0', true, 'IPv4 private 10/8' ],
201  [ '10.255.255.255', true, 'IPv4 private 10/8' ],
202  [ '192.168.1.1', true, 'IPv4 private 192.168/16' ],
203  [ '203.0.113.0', true, 'IPv4 example' ],
204  [ '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff', true, 'IPv6 example' ],
205  // Not valid IPs but classified as such by MediaWiki for negated asserting
206  // of whether this might be the identifier of a logged-out user or whether
207  // to allow usernames like it.
208  [ '300.300.300.300', true, 'Looks too much like an IPv4 address' ],
209  [ '203.0.113.xxx', true, 'Assigned by UseMod to cloaked logged-out users' ],
210  ];
211  }
212 
217  public function testIsValidUserName( $username, $result, $message ) {
218  $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message );
219  }
220 
221  public static function provideUserNames() {
222  return [
223  [ '', false, 'Empty string' ],
224  [ ' ', false, 'Blank space' ],
225  [ 'abcd', false, 'Starts with small letter' ],
226  [ 'Ab/cd', false, 'Contains slash' ],
227  [ 'Ab cd', true, 'Whitespace' ],
228  [ '192.168.1.1', false, 'IP' ],
229  [ '116.17.184.5/32', false, 'IP range' ],
230  [ '::e:f:2001/96', false, 'IPv6 range' ],
231  [ 'User:Abcd', false, 'Reserved Namespace' ],
232  [ '12abcd232', true, 'Starts with Numbers' ],
233  [ '?abcd', true, 'Start with ? mark' ],
234  [ '#abcd', false, 'Start with #' ],
235  [ 'Abcdകഖഗഘ', true, ' Mixed scripts' ],
236  [ 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ],
237  [ 'Ab cd', false, ' Ideographic space' ],
238  [ '300.300.300.300', false, 'Looks too much like an IPv4 address' ],
239  [ '302.113.311.900', false, 'Looks too much like an IPv4 address' ],
240  [ '203.0.113.xxx', false, 'Reserved for usage by UseMod for cloaked logged-out users' ],
241  ];
242  }
243 
249  public function testGetEditCount() {
250  $user = $this->getMutableTestUser()->getUser();
251 
252  // let the user have a few (3) edits
253  $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
254  for ( $i = 0; $i < 3; $i++ ) {
255  $page->doEditContent(
256  ContentHandler::makeContent( (string)$i, $page->getTitle() ),
257  'test',
258  0,
259  false,
260  $user
261  );
262  }
263 
264  $this->assertEquals(
265  3,
266  $user->getEditCount(),
267  'After three edits, the user edit count should be 3'
268  );
269 
270  // increase the edit count
271  $user->incEditCount();
273 
274  $this->assertEquals(
275  4,
276  $user->getEditCount(),
277  'After increasing the edit count manually, the user edit count should be 4'
278  );
279  }
280 
286  public function testGetEditCountForAnons() {
287  $user = User::newFromName( 'Anonymous' );
288 
289  $this->assertNull(
290  $user->getEditCount(),
291  'Edit count starts null for anonymous users.'
292  );
293 
294  $user->incEditCount();
295 
296  $this->assertNull(
297  $user->getEditCount(),
298  'Edit count remains null for anonymous users despite calls to increase it.'
299  );
300  }
301 
307  public function testIncEditCount() {
308  $user = $this->getMutableTestUser()->getUser();
309  $user->incEditCount();
310 
311  $reloadedUser = User::newFromId( $user->getId() );
312  $reloadedUser->incEditCount();
313 
314  $this->assertEquals(
315  2,
316  $reloadedUser->getEditCount(),
317  'Increasing the edit count after a fresh load leaves the object up to date.'
318  );
319  }
320 
326  public function testOptions() {
327  $user = $this->getMutableTestUser()->getUser();
328 
329  $user->setOption( 'userjs-someoption', 'test' );
330  $user->setOption( 'rclimit', 200 );
331  $user->setOption( 'wpwatchlistdays', '0' );
332  $user->saveSettings();
333 
335  $user->load( User::READ_LATEST );
336  $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
337  $this->assertEquals( 200, $user->getOption( 'rclimit' ) );
338 
339  $user = User::newFromName( $user->getName() );
340  MediaWikiServices::getInstance()->getMainWANObjectCache()->clearProcessCache();
341  $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
342  $this->assertEquals( 200, $user->getOption( 'rclimit' ) );
343 
344  // Check that an option saved as a string '0' is returned as an integer.
345  $user = User::newFromName( $user->getName() );
346  $user->load( User::READ_LATEST );
347  $this->assertSame( 0, $user->getOption( 'wpwatchlistdays' ) );
348  }
349 
355  public function testAnonOptions() {
356  global $wgDefaultUserOptions;
357  $this->user->setOption( 'userjs-someoption', 'test' );
358  $this->assertEquals( $wgDefaultUserOptions['rclimit'], $this->user->getOption( 'rclimit' ) );
359  $this->assertEquals( 'test', $this->user->getOption( 'userjs-someoption' ) );
360  }
361 
371  public function testCheckPasswordValidity() {
372  $this->setMwGlobals( [
373  'wgPasswordPolicy' => [
374  'policies' => [
375  'sysop' => [
376  'MinimalPasswordLength' => 8,
377  'MinimumPasswordLengthToLogin' => 1,
378  'PasswordCannotMatchUsername' => 1,
379  ],
380  'default' => [
381  'MinimalPasswordLength' => 6,
382  'PasswordCannotMatchUsername' => true,
383  'PasswordCannotMatchBlacklist' => true,
384  'MaximalPasswordLength' => 40,
385  ],
386  ],
387  'checks' => [
388  'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
389  'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
390  'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
391  'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
392  'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
393  ],
394  ],
395  ] );
396  $this->hideDeprecated( 'User::getPasswordValidity' );
397 
398  $user = static::getTestUser()->getUser();
399 
400  // Sanity
401  $this->assertTrue( $user->isValidPassword( 'Password1234' ) );
402 
403  // Minimum length
404  $this->assertFalse( $user->isValidPassword( 'a' ) );
405  $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
406  $this->assertTrue( $user->checkPasswordValidity( 'a' )->isOK() );
407  $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
408 
409  // Maximum length
410  $longPass = str_repeat( 'a', 41 );
411  $this->assertFalse( $user->isValidPassword( $longPass ) );
412  $this->assertFalse( $user->checkPasswordValidity( $longPass )->isGood() );
413  $this->assertFalse( $user->checkPasswordValidity( $longPass )->isOK() );
414  $this->assertEquals( 'passwordtoolong', $user->getPasswordValidity( $longPass ) );
415 
416  // Matches username
417  $this->assertFalse( $user->checkPasswordValidity( $user->getName() )->isGood() );
418  $this->assertTrue( $user->checkPasswordValidity( $user->getName() )->isOK() );
419  $this->assertEquals( 'password-name-match', $user->getPasswordValidity( $user->getName() ) );
420 
421  // On the forbidden list
422  $user = User::newFromName( 'Useruser' );
423  $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
424  $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
425  }
426 
431  public function testGetCanonicalName( $name, $expectedArray ) {
432  // fake interwiki map for the 'Interwiki prefix' testcase
433  $this->mergeMwGlobalArrayValue( 'wgHooks', [
434  'InterwikiLoadPrefix' => [
435  function ( $prefix, &$iwdata ) {
436  if ( $prefix === 'interwiki' ) {
437  $iwdata = [
438  'iw_url' => 'http://example.com/',
439  'iw_local' => 0,
440  'iw_trans' => 0,
441  ];
442  return false;
443  }
444  },
445  ],
446  ] );
447 
448  foreach ( $expectedArray as $validate => $expected ) {
449  $this->assertEquals(
450  $expected,
451  User::getCanonicalName( $name, $validate === 'false' ? false : $validate ), $validate );
452  }
453  }
454 
455  public static function provideGetCanonicalName() {
456  return [
457  'Leading space' => [ ' Leading space', [ 'creatable' => 'Leading space' ] ],
458  'Trailing space ' => [ 'Trailing space ', [ 'creatable' => 'Trailing space' ] ],
459  'Namespace prefix' => [ 'Talk:Username', [ 'creatable' => false, 'usable' => false,
460  'valid' => false, 'false' => 'Talk:Username' ] ],
461  'Interwiki prefix' => [ 'interwiki:Username', [ 'creatable' => false, 'usable' => false,
462  'valid' => false, 'false' => 'Interwiki:Username' ] ],
463  'With hash' => [ 'name with # hash', [ 'creatable' => false, 'usable' => false ] ],
464  'Multi spaces' => [ 'Multi spaces', [ 'creatable' => 'Multi spaces',
465  'usable' => 'Multi spaces' ] ],
466  'Lowercase' => [ 'lowercase', [ 'creatable' => 'Lowercase' ] ],
467  'Invalid character' => [ 'in[]valid', [ 'creatable' => false, 'usable' => false,
468  'valid' => false, 'false' => 'In[]valid' ] ],
469  'With slash' => [ 'with / slash', [ 'creatable' => false, 'usable' => false, 'valid' => false,
470  'false' => 'With / slash' ] ],
471  ];
472  }
473 
477  public function testEquals() {
478  $first = $this->getMutableTestUser()->getUser();
479  $second = User::newFromName( $first->getName() );
480 
481  $this->assertTrue( $first->equals( $first ) );
482  $this->assertTrue( $first->equals( $second ) );
483  $this->assertTrue( $second->equals( $first ) );
484 
485  $third = $this->getMutableTestUser()->getUser();
486  $fourth = $this->getMutableTestUser()->getUser();
487 
488  $this->assertFalse( $third->equals( $fourth ) );
489  $this->assertFalse( $fourth->equals( $third ) );
490 
491  // Test users loaded from db with id
492  $user = $this->getMutableTestUser()->getUser();
493  $fifth = User::newFromId( $user->getId() );
494  $sixth = User::newFromName( $user->getName() );
495  $this->assertTrue( $fifth->equals( $sixth ) );
496  }
497 
501  public function testGetId() {
502  $user = static::getTestUser()->getUser();
503  $this->assertTrue( $user->getId() > 0 );
504  }
505 
510  public function testLoggedIn() {
511  $user = $this->getMutableTestUser()->getUser();
512  $this->assertTrue( $user->isLoggedIn() );
513  $this->assertFalse( $user->isAnon() );
514 
515  // Non-existent users are perceived as anonymous
516  $user = User::newFromName( 'UTNonexistent' );
517  $this->assertFalse( $user->isLoggedIn() );
518  $this->assertTrue( $user->isAnon() );
519 
520  $user = new User;
521  $this->assertFalse( $user->isLoggedIn() );
522  $this->assertTrue( $user->isAnon() );
523  }
524 
528  public function testCheckAndSetTouched() {
529  $user = $this->getMutableTestUser()->getUser();
530  $user = TestingAccessWrapper::newFromObject( $user );
531  $this->assertTrue( $user->isLoggedIn() );
532 
533  $touched = $user->getDBTouched();
534  $this->assertTrue(
535  $user->checkAndSetTouched(), "checkAndSetTouched() succedeed" );
536  $this->assertGreaterThan(
537  $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
538 
539  $touched = $user->getDBTouched();
540  $this->assertTrue(
541  $user->checkAndSetTouched(), "checkAndSetTouched() succedeed #2" );
542  $this->assertGreaterThan(
543  $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
544  }
545 
549  public function testFindUsersByGroup() {
550  // FIXME: fails under postgres
551  $this->markTestSkippedIfDbType( 'postgres' );
552 
554  $this->assertEquals( 0, iterator_count( $users ) );
555 
556  $users = User::findUsersByGroup( 'foo' );
557  $this->assertEquals( 0, iterator_count( $users ) );
558 
559  $user = $this->getMutableTestUser( [ 'foo' ] )->getUser();
560  $users = User::findUsersByGroup( 'foo' );
561  $this->assertEquals( 1, iterator_count( $users ) );
562  $users->rewind();
563  $this->assertTrue( $user->equals( $users->current() ) );
564 
565  // arguments have OR relationship
566  $user2 = $this->getMutableTestUser( [ 'bar' ] )->getUser();
567  $users = User::findUsersByGroup( [ 'foo', 'bar' ] );
568  $this->assertEquals( 2, iterator_count( $users ) );
569  $users->rewind();
570  $this->assertTrue( $user->equals( $users->current() ) );
571  $users->next();
572  $this->assertTrue( $user2->equals( $users->current() ) );
573 
574  // users are not duplicated
575  $user = $this->getMutableTestUser( [ 'baz', 'boom' ] )->getUser();
576  $users = User::findUsersByGroup( [ 'baz', 'boom' ] );
577  $this->assertEquals( 1, iterator_count( $users ) );
578  $users->rewind();
579  $this->assertTrue( $user->equals( $users->current() ) );
580  }
581 
588  public function testAutoblockCookies() {
589  // Set up the bits of global configuration that we use.
590  $this->setMwGlobals( [
591  'wgCookieSetOnAutoblock' => true,
592  'wgCookiePrefix' => 'wmsitetitle',
593  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
594  ] );
595 
596  // Unregister the hooks for proper unit testing
597  $this->mergeMwGlobalArrayValue( 'wgHooks', [
598  'PerformRetroactiveAutoblock' => []
599  ] );
600 
601  // 1. Log in a test user, and block them.
602  $user1tmp = $this->getTestUser()->getUser();
603  $request1 = new FauxRequest();
604  $request1->getSession()->setUser( $user1tmp );
605  $expiryFiveHours = wfTimestamp() + ( 5 * 60 * 60 );
606  $block = new Block( [
607  'enableAutoblock' => true,
608  'expiry' => wfTimestamp( TS_MW, $expiryFiveHours ),
609  ] );
610  $block->setBlocker( $this->getTestSysop()->getUser() );
611  $block->setTarget( $user1tmp );
612  $res = $block->insert();
613  $this->assertTrue( (bool)$res['id'], 'Failed to insert block' );
614  $user1 = User::newFromSession( $request1 );
615  $user1->mBlock = $block;
616  $user1->load();
617 
618  // Confirm that the block has been applied as required.
619  $this->assertTrue( $user1->isLoggedIn() );
620  $this->assertTrue( $user1->isBlocked() );
621  $this->assertEquals( Block::TYPE_USER, $block->getType() );
622  $this->assertTrue( $block->isAutoblocking() );
623  $this->assertGreaterThanOrEqual( 1, $block->getId() );
624 
625  // Test for the desired cookie name, value, and expiry.
626  $cookies = $request1->response()->getCookies();
627  $this->assertArrayHasKey( 'wmsitetitleBlockID', $cookies );
628  $this->assertEquals( $expiryFiveHours, $cookies['wmsitetitleBlockID']['expire'] );
629  $cookieValue = Block::getIdFromCookieValue( $cookies['wmsitetitleBlockID']['value'] );
630  $this->assertEquals( $block->getId(), $cookieValue );
631 
632  // 2. Create a new request, set the cookies, and see if the (anon) user is blocked.
633  $request2 = new FauxRequest();
634  $request2->setCookie( 'BlockID', $block->getCookieValue() );
635  $user2 = User::newFromSession( $request2 );
636  $user2->load();
637  $this->assertNotEquals( $user1->getId(), $user2->getId() );
638  $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
639  $this->assertTrue( $user2->isAnon() );
640  $this->assertFalse( $user2->isLoggedIn() );
641  $this->assertTrue( $user2->isBlocked() );
642  // Non-strict type-check.
643  $this->assertEquals( true, $user2->getBlock()->isAutoblocking(), 'Autoblock does not work' );
644  // Can't directly compare the objects because of member type differences.
645  // One day this will work: $this->assertEquals( $block, $user2->getBlock() );
646  $this->assertEquals( $block->getId(), $user2->getBlock()->getId() );
647  $this->assertEquals( $block->getExpiry(), $user2->getBlock()->getExpiry() );
648 
649  // 3. Finally, set up a request as a new user, and the block should still be applied.
650  $user3tmp = $this->getTestUser()->getUser();
651  $request3 = new FauxRequest();
652  $request3->getSession()->setUser( $user3tmp );
653  $request3->setCookie( 'BlockID', $block->getId() );
654  $user3 = User::newFromSession( $request3 );
655  $user3->load();
656  $this->assertTrue( $user3->isLoggedIn() );
657  $this->assertTrue( $user3->isBlocked() );
658  $this->assertEquals( true, $user3->getBlock()->isAutoblocking() ); // Non-strict type-check.
659 
660  // Clean up.
661  $block->delete();
662  }
663 
669  public function testAutoblockCookiesDisabled() {
670  // Set up the bits of global configuration that we use.
671  $this->setMwGlobals( [
672  'wgCookieSetOnAutoblock' => false,
673  'wgCookiePrefix' => 'wm_no_cookies',
674  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
675  ] );
676 
677  // Unregister the hooks for proper unit testing
678  $this->mergeMwGlobalArrayValue( 'wgHooks', [
679  'PerformRetroactiveAutoblock' => []
680  ] );
681 
682  // 1. Log in a test user, and block them.
683  $testUser = $this->getTestUser()->getUser();
684  $request1 = new FauxRequest();
685  $request1->getSession()->setUser( $testUser );
686  $block = new Block( [ 'enableAutoblock' => true ] );
687  $block->setBlocker( $this->getTestSysop()->getUser() );
688  $block->setTarget( $testUser );
689  $res = $block->insert();
690  $this->assertTrue( (bool)$res['id'], 'Failed to insert block' );
691  $user = User::newFromSession( $request1 );
692  $user->mBlock = $block;
693  $user->load();
694 
695  // 2. Test that the cookie IS NOT present.
696  $this->assertTrue( $user->isLoggedIn() );
697  $this->assertTrue( $user->isBlocked() );
698  $this->assertEquals( Block::TYPE_USER, $block->getType() );
699  $this->assertTrue( $block->isAutoblocking() );
700  $this->assertGreaterThanOrEqual( 1, $user->getBlockId() );
701  $this->assertGreaterThanOrEqual( $block->getId(), $user->getBlockId() );
702  $cookies = $request1->response()->getCookies();
703  $this->assertArrayNotHasKey( 'wm_no_cookiesBlockID', $cookies );
704 
705  // Clean up.
706  $block->delete();
707  }
708 
716  $this->setMwGlobals( [
717  'wgCookieSetOnAutoblock' => true,
718  'wgCookiePrefix' => 'wm_infinite_block',
719  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
720  ] );
721 
722  // Unregister the hooks for proper unit testing
723  $this->mergeMwGlobalArrayValue( 'wgHooks', [
724  'PerformRetroactiveAutoblock' => []
725  ] );
726 
727  // 1. Log in a test user, and block them indefinitely.
728  $user1Tmp = $this->getTestUser()->getUser();
729  $request1 = new FauxRequest();
730  $request1->getSession()->setUser( $user1Tmp );
731  $block = new Block( [ 'enableAutoblock' => true, 'expiry' => 'infinity' ] );
732  $block->setBlocker( $this->getTestSysop()->getUser() );
733  $block->setTarget( $user1Tmp );
734  $res = $block->insert();
735  $this->assertTrue( (bool)$res['id'], 'Failed to insert block' );
736  $user1 = User::newFromSession( $request1 );
737  $user1->mBlock = $block;
738  $user1->load();
739 
740  // 2. Test the cookie's expiry timestamp.
741  $this->assertTrue( $user1->isLoggedIn() );
742  $this->assertTrue( $user1->isBlocked() );
743  $this->assertEquals( Block::TYPE_USER, $block->getType() );
744  $this->assertTrue( $block->isAutoblocking() );
745  $this->assertGreaterThanOrEqual( 1, $user1->getBlockId() );
746  $cookies = $request1->response()->getCookies();
747  // Test the cookie's expiry to the nearest minute.
748  $this->assertArrayHasKey( 'wm_infinite_blockBlockID', $cookies );
749  $expOneDay = wfTimestamp() + ( 24 * 60 * 60 );
750  // Check for expiry dates in a 10-second window, to account for slow testing.
751  $this->assertEquals(
752  $expOneDay,
753  $cookies['wm_infinite_blockBlockID']['expire'],
754  'Expiry date',
755  5.0
756  );
757 
758  // 3. Change the block's expiry (to 2 hours), and the cookie's should be changed also.
759  $newExpiry = wfTimestamp() + 2 * 60 * 60;
760  $block->setExpiry( wfTimestamp( TS_MW, $newExpiry ) );
761  $block->update();
762  $user2tmp = $this->getTestUser()->getUser();
763  $request2 = new FauxRequest();
764  $request2->getSession()->setUser( $user2tmp );
765  $user2 = User::newFromSession( $request2 );
766  $user2->mBlock = $block;
767  $user2->load();
768  $cookies = $request2->response()->getCookies();
769  $this->assertEquals( wfTimestamp( TS_MW, $newExpiry ), $block->getExpiry() );
770  $this->assertEquals( $newExpiry, $cookies['wm_infinite_blockBlockID']['expire'] );
771 
772  // Clean up.
773  $block->delete();
774  }
775 
779  public function testSoftBlockRanges() {
780  $setSessionUser = function ( User $user, WebRequest $request ) {
781  $this->setMwGlobals( 'wgUser', $user );
782  RequestContext::getMain()->setUser( $user );
783  RequestContext::getMain()->setRequest( $request );
784  TestingAccessWrapper::newFromObject( $user )->mRequest = $request;
785  $request->getSession()->setUser( $user );
786  };
787  $this->setMwGlobals( 'wgSoftBlockRanges', [ '10.0.0.0/8' ] );
788 
789  // IP isn't in $wgSoftBlockRanges
790  $wgUser = new User();
791  $request = new FauxRequest();
792  $request->setIP( '192.168.0.1' );
793  $setSessionUser( $wgUser, $request );
794  $this->assertNull( $wgUser->getBlock() );
795 
796  // IP is in $wgSoftBlockRanges
797  $wgUser = new User();
798  $request = new FauxRequest();
799  $request->setIP( '10.20.30.40' );
800  $setSessionUser( $wgUser, $request );
801  $block = $wgUser->getBlock();
802  $this->assertInstanceOf( Block::class, $block );
803  $this->assertSame( 'wgSoftBlockRanges', $block->getSystemBlockType() );
804 
805  // Make sure the block is really soft
806  $wgUser = $this->getTestUser()->getUser();
807  $request = new FauxRequest();
808  $request->setIP( '10.20.30.40' );
809  $setSessionUser( $wgUser, $request );
810  $this->assertFalse( $wgUser->isAnon(), 'sanity check' );
811  $this->assertNull( $wgUser->getBlock() );
812  }
813 
818  public function testAutoblockCookieInauthentic() {
819  // Set up the bits of global configuration that we use.
820  $this->setMwGlobals( [
821  'wgCookieSetOnAutoblock' => true,
822  'wgCookiePrefix' => 'wmsitetitle',
823  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
824  ] );
825 
826  // Unregister the hooks for proper unit testing
827  $this->mergeMwGlobalArrayValue( 'wgHooks', [
828  'PerformRetroactiveAutoblock' => []
829  ] );
830 
831  // 1. Log in a blocked test user.
832  $user1tmp = $this->getTestUser()->getUser();
833  $request1 = new FauxRequest();
834  $request1->getSession()->setUser( $user1tmp );
835  $block = new Block( [ 'enableAutoblock' => true ] );
836  $block->setBlocker( $this->getTestSysop()->getUser() );
837  $block->setTarget( $user1tmp );
838  $res = $block->insert();
839  $this->assertTrue( (bool)$res['id'], 'Failed to insert block' );
840  $user1 = User::newFromSession( $request1 );
841  $user1->mBlock = $block;
842  $user1->load();
843 
844  // 2. Create a new request, set the cookie to an invalid value, and make sure the (anon)
845  // user not blocked.
846  $request2 = new FauxRequest();
847  $request2->setCookie( 'BlockID', $block->getId() . '!zzzzzzz' );
848  $user2 = User::newFromSession( $request2 );
849  $user2->load();
850  $this->assertTrue( $user2->isAnon() );
851  $this->assertFalse( $user2->isLoggedIn() );
852  $this->assertFalse( $user2->isBlocked() );
853 
854  // Clean up.
855  $block->delete();
856  }
857 
863  public function testAutoblockCookieNoSecretKey() {
864  // Set up the bits of global configuration that we use.
865  $this->setMwGlobals( [
866  'wgCookieSetOnAutoblock' => true,
867  'wgCookiePrefix' => 'wmsitetitle',
868  'wgSecretKey' => null,
869  ] );
870 
871  // Unregister the hooks for proper unit testing
872  $this->mergeMwGlobalArrayValue( 'wgHooks', [
873  'PerformRetroactiveAutoblock' => []
874  ] );
875 
876  // 1. Log in a blocked test user.
877  $user1tmp = $this->getTestUser()->getUser();
878  $request1 = new FauxRequest();
879  $request1->getSession()->setUser( $user1tmp );
880  $block = new Block( [ 'enableAutoblock' => true ] );
881  $block->setBlocker( $this->getTestSysop()->getUser() );
882  $block->setTarget( $user1tmp );
883  $res = $block->insert();
884  $this->assertTrue( (bool)$res['id'], 'Failed to insert block' );
885  $user1 = User::newFromSession( $request1 );
886  $user1->mBlock = $block;
887  $user1->load();
888  $this->assertTrue( $user1->isBlocked() );
889 
890  // 2. Create a new request, set the cookie to just the block ID, and the user should
891  // still get blocked when they log in again.
892  $request2 = new FauxRequest();
893  $request2->setCookie( 'BlockID', $block->getId() );
894  $user2 = User::newFromSession( $request2 );
895  $user2->load();
896  $this->assertNotEquals( $user1->getId(), $user2->getId() );
897  $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
898  $this->assertTrue( $user2->isAnon() );
899  $this->assertFalse( $user2->isLoggedIn() );
900  $this->assertTrue( $user2->isBlocked() );
901  $this->assertEquals( true, $user2->getBlock()->isAutoblocking() ); // Non-strict type-check.
902 
903  // Clean up.
904  $block->delete();
905  }
906 
910  public function testIsPingLimitable() {
911  $request = new FauxRequest();
912  $request->setIP( '1.2.3.4' );
914 
915  $this->setMwGlobals( 'wgRateLimitsExcludedIPs', [] );
916  $this->assertTrue( $user->isPingLimitable() );
917 
918  $this->setMwGlobals( 'wgRateLimitsExcludedIPs', [ '1.2.3.4' ] );
919  $this->assertFalse( $user->isPingLimitable() );
920 
921  $this->setMwGlobals( 'wgRateLimitsExcludedIPs', [ '1.2.3.0/8' ] );
922  $this->assertFalse( $user->isPingLimitable() );
923 
924  $this->setMwGlobals( 'wgRateLimitsExcludedIPs', [] );
925  $noRateLimitUser = $this->getMockBuilder( User::class )->disableOriginalConstructor()
926  ->setMethods( [ 'getIP', 'getRights' ] )->getMock();
927  $noRateLimitUser->expects( $this->any() )->method( 'getIP' )->willReturn( '1.2.3.4' );
928  $noRateLimitUser->expects( $this->any() )->method( 'getRights' )->willReturn( [ 'noratelimit' ] );
929  $this->assertFalse( $noRateLimitUser->isPingLimitable() );
930  }
931 
932  public function provideExperienceLevel() {
933  return [
934  [ 2, 2, 'newcomer' ],
935  [ 12, 3, 'newcomer' ],
936  [ 8, 5, 'newcomer' ],
937  [ 15, 10, 'learner' ],
938  [ 450, 20, 'learner' ],
939  [ 460, 33, 'learner' ],
940  [ 525, 28, 'learner' ],
941  [ 538, 33, 'experienced' ],
942  ];
943  }
944 
949  public function testExperienceLevel( $editCount, $memberSince, $expLevel ) {
950  $this->setMwGlobals( [
951  'wgLearnerEdits' => 10,
952  'wgLearnerMemberSince' => 4,
953  'wgExperiencedUserEdits' => 500,
954  'wgExperiencedUserMemberSince' => 30,
955  ] );
956 
957  $db = wfGetDB( DB_MASTER );
958  $userQuery = User::getQueryInfo();
959  $row = $db->selectRow(
960  $userQuery['tables'],
961  $userQuery['fields'],
962  [ 'user_id' => $this->getTestUser()->getUser()->getId() ],
963  __METHOD__,
964  [],
965  $userQuery['joins']
966  );
967  $row->user_editcount = $editCount;
968  $row->user_registration = $db->timestamp( time() - $memberSince * 86400 );
969  $user = User::newFromRow( $row );
970 
971  $this->assertEquals( $expLevel, $user->getExperienceLevel() );
972  }
973 
977  public function testExperienceLevelAnon() {
978  $user = User::newFromName( '10.11.12.13', false );
979 
980  $this->assertFalse( $user->getExperienceLevel() );
981  }
982 
983  public static function provideIsLocallBlockedProxy() {
984  return [
985  [ '1.2.3.4', '1.2.3.4' ],
986  [ '1.2.3.4', '1.2.3.0/16' ],
987  ];
988  }
989 
994  public function testIsLocallyBlockedProxy( $ip, $blockListEntry ) {
995  $this->setMwGlobals(
996  'wgProxyList', []
997  );
998  $this->assertFalse( User::isLocallyBlockedProxy( $ip ) );
999 
1000  $this->setMwGlobals(
1001  'wgProxyList',
1002  [
1003  $blockListEntry
1004  ]
1005  );
1006  $this->assertTrue( User::isLocallyBlockedProxy( $ip ) );
1007 
1008  $this->setMwGlobals(
1009  'wgProxyList',
1010  [
1011  'test' => $blockListEntry
1012  ]
1013  );
1014  $this->assertTrue( User::isLocallyBlockedProxy( $ip ) );
1015 
1016  $this->hideDeprecated(
1017  'IP addresses in the keys of $wgProxyList (found the following IP ' .
1018  'addresses in keys: ' . $blockListEntry . ', please move them to values)'
1019  );
1020  $this->setMwGlobals(
1021  'wgProxyList',
1022  [
1023  $blockListEntry => 'test'
1024  ]
1025  );
1026  $this->assertTrue( User::isLocallyBlockedProxy( $ip ) );
1027  }
1028 
1032  public function testActorId() {
1033  $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
1034  $this->hideDeprecated( 'User::selectFields' );
1035 
1036  // Newly-created user has an actor ID
1037  $user = User::createNew( 'UserTestActorId1' );
1038  $id = $user->getId();
1039  $this->assertTrue( $user->getActorId() > 0, 'User::createNew sets an actor ID' );
1040 
1041  $user = User::newFromName( 'UserTestActorId2' );
1042  $user->addToDatabase();
1043  $this->assertTrue( $user->getActorId() > 0, 'User::addToDatabase sets an actor ID' );
1044 
1045  $user = User::newFromName( 'UserTestActorId1' );
1046  $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by name' );
1047 
1048  $user = User::newFromId( $id );
1049  $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' );
1050 
1051  $user2 = User::newFromActorId( $user->getActorId() );
1052  $this->assertEquals( $user->getId(), $user2->getId(),
1053  'User::newFromActorId works for an existing user' );
1054 
1055  $row = $this->db->selectRow( 'user', User::selectFields(), [ 'user_id' => $id ], __METHOD__ );
1056  $user = User::newFromRow( $row );
1057  $this->assertTrue( $user->getActorId() > 0,
1058  'Actor ID can be retrieved for user loaded with User::selectFields()' );
1059 
1060  $this->db->delete( 'actor', [ 'actor_user' => $id ], __METHOD__ );
1061  User::purge( $domain, $id );
1062  // Because WANObjectCache->delete() stupidly doesn't delete from the process cache.
1063  ObjectCache::getMainWANInstance()->clearProcessCache();
1064 
1065  $user = User::newFromId( $id );
1066  $this->assertFalse( $user->getActorId() > 0, 'No Actor ID by default if none in database' );
1067  $this->assertTrue( $user->getActorId( $this->db ) > 0, 'Actor ID can be created if none in db' );
1068 
1069  $user->setName( 'UserTestActorId4-renamed' );
1070  $user->saveSettings();
1071  $this->assertEquals(
1072  $user->getName(),
1073  $this->db->selectField(
1074  'actor', 'actor_name', [ 'actor_id' => $user->getActorId() ], __METHOD__
1075  ),
1076  'User::saveSettings updates actor table for name change'
1077  );
1078 
1079  // For sanity
1080  $ip = '192.168.12.34';
1081  $this->db->delete( 'actor', [ 'actor_name' => $ip ], __METHOD__ );
1082 
1083  $user = User::newFromName( $ip, false );
1084  $this->assertFalse( $user->getActorId() > 0, 'Anonymous user has no actor ID by default' );
1085  $this->assertTrue( $user->getActorId( $this->db ) > 0,
1086  'Actor ID can be created for an anonymous user' );
1087 
1088  $user = User::newFromName( $ip, false );
1089  $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be loaded for an anonymous user' );
1090  $user2 = User::newFromActorId( $user->getActorId() );
1091  $this->assertEquals( $user->getName(), $user2->getName(),
1092  'User::newFromActorId works for an anonymous user' );
1093  }
1094 
1098  public function testNewFromAnyId() {
1099  // Registered user
1100  $user = $this->getTestUser()->getUser();
1101  for ( $i = 1; $i <= 7; $i++ ) {
1102  $test = User::newFromAnyId(
1103  ( $i & 1 ) ? $user->getId() : null,
1104  ( $i & 2 ) ? $user->getName() : null,
1105  ( $i & 4 ) ? $user->getActorId() : null
1106  );
1107  $this->assertSame( $user->getId(), $test->getId() );
1108  $this->assertSame( $user->getName(), $test->getName() );
1109  $this->assertSame( $user->getActorId(), $test->getActorId() );
1110  }
1111 
1112  // Anon user. Can't load by only user ID when that's 0.
1113  $user = User::newFromName( '192.168.12.34', false );
1114  $user->getActorId( $this->db ); // Make sure an actor ID exists
1115 
1116  $test = User::newFromAnyId( null, '192.168.12.34', null );
1117  $this->assertSame( $user->getId(), $test->getId() );
1118  $this->assertSame( $user->getName(), $test->getName() );
1119  $this->assertSame( $user->getActorId(), $test->getActorId() );
1120  $test = User::newFromAnyId( null, null, $user->getActorId() );
1121  $this->assertSame( $user->getId(), $test->getId() );
1122  $this->assertSame( $user->getName(), $test->getName() );
1123  $this->assertSame( $user->getActorId(), $test->getActorId() );
1124 
1125  // Bogus data should still "work" as long as nothing triggers a ->load(),
1126  // and accessing the specified data shouldn't do that.
1127  $test = User::newFromAnyId( 123456, 'Bogus', 654321 );
1128  $this->assertSame( 123456, $test->getId() );
1129  $this->assertSame( 'Bogus', $test->getName() );
1130  $this->assertSame( 654321, $test->getActorId() );
1131 
1132  // Exceptional cases
1133  try {
1135  $this->fail( 'Expected exception not thrown' );
1136  } catch ( InvalidArgumentException $ex ) {
1137  }
1138  try {
1139  User::newFromAnyId( 0, null, 0 );
1140  $this->fail( 'Expected exception not thrown' );
1141  } catch ( InvalidArgumentException $ex ) {
1142  }
1143  }
1144 
1148  public function testNewFromIdentity() {
1149  // Registered user
1150  $user = $this->getTestUser()->getUser();
1151 
1152  $this->assertSame( $user, User::newFromIdentity( $user ) );
1153 
1154  // ID only
1155  $identity = new UserIdentityValue( $user->getId(), '', 0 );
1156  $result = User::newFromIdentity( $identity );
1157  $this->assertInstanceOf( User::class, $result );
1158  $this->assertSame( $user->getId(), $result->getId(), 'ID' );
1159  $this->assertSame( $user->getName(), $result->getName(), 'Name' );
1160  $this->assertSame( $user->getActorId(), $result->getActorId(), 'Actor' );
1161 
1162  // Name only
1163  $identity = new UserIdentityValue( 0, $user->getName(), 0 );
1164  $result = User::newFromIdentity( $identity );
1165  $this->assertInstanceOf( User::class, $result );
1166  $this->assertSame( $user->getId(), $result->getId(), 'ID' );
1167  $this->assertSame( $user->getName(), $result->getName(), 'Name' );
1168  $this->assertSame( $user->getActorId(), $result->getActorId(), 'Actor' );
1169 
1170  // Actor only
1171  $identity = new UserIdentityValue( 0, '', $user->getActorId() );
1172  $result = User::newFromIdentity( $identity );
1173  $this->assertInstanceOf( User::class, $result );
1174  $this->assertSame( $user->getId(), $result->getId(), 'ID' );
1175  $this->assertSame( $user->getName(), $result->getName(), 'Name' );
1176  $this->assertSame( $user->getActorId(), $result->getActorId(), 'Actor' );
1177  }
1178 
1187  public function testBlockInstanceCache() {
1188  // First, check the user isn't blocked
1189  $user = $this->getMutableTestUser()->getUser();
1191  $this->assertNull( $user->getBlock( false ), 'sanity check' );
1192  $this->assertSame( '', $user->blockedBy(), 'sanity check' );
1193  $this->assertSame( '', $user->blockedFor(), 'sanity check' );
1194  $this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
1195  $this->assertFalse( $user->isBlockedFrom( $ut ), 'sanity check' );
1196 
1197  // Block the user
1198  $blocker = $this->getTestSysop()->getUser();
1199  $block = new Block( [
1200  'hideName' => true,
1201  'allowUsertalk' => false,
1202  'reason' => 'Because',
1203  ] );
1204  $block->setTarget( $user );
1205  $block->setBlocker( $blocker );
1206  $res = $block->insert();
1207  $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
1208 
1209  // Clear cache and confirm it loaded the block properly
1211  $this->assertInstanceOf( Block::class, $user->getBlock( false ) );
1212  $this->assertSame( $blocker->getName(), $user->blockedBy() );
1213  $this->assertSame( 'Because', $user->blockedFor() );
1214  $this->assertTrue( (bool)$user->isHidden() );
1215  $this->assertTrue( $user->isBlockedFrom( $ut ) );
1216 
1217  // Unblock
1218  $block->delete();
1219 
1220  // Clear cache and confirm it loaded the not-blocked properly
1222  $this->assertNull( $user->getBlock( false ) );
1223  $this->assertSame( '', $user->blockedBy() );
1224  $this->assertSame( '', $user->blockedFor() );
1225  $this->assertFalse( (bool)$user->isHidden() );
1226  $this->assertFalse( $user->isBlockedFrom( $ut ) );
1227  }
1228 
1239  public function testIsBlockedFrom( $title, $expect, array $options = [] ) {
1240  $this->setMwGlobals( [
1241  'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
1242  ] );
1243 
1244  $user = $this->getTestUser()->getUser();
1245 
1246  if ( $title === self::USER_TALK_PAGE ) {
1247  $title = $user->getTalkPage();
1248  } else {
1250  }
1251 
1252  $restrictions = [];
1253  foreach ( $options['pageRestrictions'] ?? [] as $pagestr ) {
1254  $page = $this->getExistingTestPage(
1255  $pagestr === self::USER_TALK_PAGE ? $user->getTalkPage() : $pagestr
1256  );
1257  $restrictions[] = new PageRestriction( 0, $page->getId() );
1258  }
1259  foreach ( $options['namespaceRestrictions'] ?? [] as $ns ) {
1260  $restrictions[] = new NamespaceRestriction( 0, $ns );
1261  }
1262 
1263  $block = new Block( [
1264  'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
1265  'allowUsertalk' => $options['allowUsertalk'] ?? false,
1266  'sitewide' => !$restrictions,
1267  ] );
1268  $block->setTarget( $user );
1269  $block->setBlocker( $this->getTestSysop()->getUser() );
1270  if ( $restrictions ) {
1271  $block->setRestrictions( $restrictions );
1272  }
1273  $block->insert();
1274 
1275  try {
1276  $this->assertSame( $expect, $user->isBlockedFrom( $title ) );
1277  } finally {
1278  $block->delete();
1279  }
1280  }
1281 
1282  public static function provideIsBlockedFrom() {
1283  return [
1284  'Sitewide block, basic operation' => [ 'Test page', true ],
1285  'Sitewide block, not allowing user talk' => [
1286  self::USER_TALK_PAGE, true, [
1287  'allowUsertalk' => false,
1288  ]
1289  ],
1290  'Sitewide block, allowing user talk' => [
1291  self::USER_TALK_PAGE, false, [
1292  'allowUsertalk' => true,
1293  ]
1294  ],
1295  'Sitewide block, allowing user talk but $wgBlockAllowsUTEdit is false' => [
1296  self::USER_TALK_PAGE, true, [
1297  'allowUsertalk' => true,
1298  'blockAllowsUTEdit' => false,
1299  ]
1300  ],
1301  'Partial block, blocking the page' => [
1302  'Test page', true, [
1303  'pageRestrictions' => [ 'Test page' ],
1304  ]
1305  ],
1306  'Partial block, not blocking the page' => [
1307  'Test page 2', false, [
1308  'pageRestrictions' => [ 'Test page' ],
1309  ]
1310  ],
1311  'Partial block, not allowing user talk but user talk page is not blocked' => [
1312  self::USER_TALK_PAGE, false, [
1313  'allowUsertalk' => false,
1314  'pageRestrictions' => [ 'Test page' ],
1315  ]
1316  ],
1317  'Partial block, allowing user talk but user talk page is blocked' => [
1318  self::USER_TALK_PAGE, true, [
1319  'allowUsertalk' => true,
1320  'pageRestrictions' => [ self::USER_TALK_PAGE ],
1321  ]
1322  ],
1323  'Partial block, user talk page is not blocked but $wgBlockAllowsUTEdit is false' => [
1324  self::USER_TALK_PAGE, false, [
1325  'allowUsertalk' => false,
1326  'pageRestrictions' => [ 'Test page' ],
1327  'blockAllowsUTEdit' => false,
1328  ]
1329  ],
1330  'Partial block, user talk page is blocked and $wgBlockAllowsUTEdit is false' => [
1331  self::USER_TALK_PAGE, true, [
1332  'allowUsertalk' => true,
1333  'pageRestrictions' => [ self::USER_TALK_PAGE ],
1334  'blockAllowsUTEdit' => false,
1335  ]
1336  ],
1337  'Partial user talk namespace block, not allowing user talk' => [
1338  self::USER_TALK_PAGE, true, [
1339  'allowUsertalk' => false,
1340  'namespaceRestrictions' => [ NS_USER_TALK ],
1341  ]
1342  ],
1343  'Partial user talk namespace block, allowing user talk' => [
1344  self::USER_TALK_PAGE, false, [
1345  'allowUsertalk' => true,
1346  'namespaceRestrictions' => [ NS_USER_TALK ],
1347  ]
1348  ],
1349  'Partial user talk namespace block, where $wgBlockAllowsUTEdit is false' => [
1350  self::USER_TALK_PAGE, true, [
1351  'allowUsertalk' => true,
1352  'namespaceRestrictions' => [ NS_USER_TALK ],
1353  'blockAllowsUTEdit' => false,
1354  ]
1355  ],
1356  ];
1357  }
1358 
1364  public function testIpBlockCookieSet() {
1365  $this->setMwGlobals( [
1366  'wgCookieSetOnIpBlock' => true,
1367  'wgCookiePrefix' => 'wiki',
1368  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
1369  ] );
1370 
1371  // setup block
1372  $block = new Block( [
1373  'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 5 * 60 * 60 ) ),
1374  ] );
1375  $block->setTarget( '1.2.3.4' );
1376  $block->setBlocker( $this->getTestSysop()->getUser() );
1377  $block->insert();
1378 
1379  // setup request
1380  $request = new FauxRequest();
1381  $request->setIP( '1.2.3.4' );
1382 
1383  // get user
1386 
1387  // test cookie was set
1388  $cookies = $request->response()->getCookies();
1389  $this->assertArrayHasKey( 'wikiBlockID', $cookies );
1390 
1391  // clean up
1392  $block->delete();
1393  }
1394 
1400  public function testIpBlockCookieNotSet() {
1401  $this->setMwGlobals( [
1402  'wgCookieSetOnIpBlock' => false,
1403  'wgCookiePrefix' => 'wiki',
1404  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
1405  ] );
1406 
1407  // setup block
1408  $block = new Block( [
1409  'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 5 * 60 * 60 ) ),
1410  ] );
1411  $block->setTarget( '1.2.3.4' );
1412  $block->setBlocker( $this->getTestSysop()->getUser() );
1413  $block->insert();
1414 
1415  // setup request
1416  $request = new FauxRequest();
1417  $request->setIP( '1.2.3.4' );
1418 
1419  // get user
1422 
1423  // test cookie was not set
1424  $cookies = $request->response()->getCookies();
1425  $this->assertArrayNotHasKey( 'wikiBlockID', $cookies );
1426 
1427  // clean up
1428  $block->delete();
1429  }
1430 
1437  $this->setMwGlobals( [
1438  'wgAutoblockExpiry' => 8000,
1439  'wgCookieSetOnIpBlock' => true,
1440  'wgCookiePrefix' => 'wiki',
1441  'wgSecretKey' => MWCryptRand::generateHex( 64, true ),
1442  ] );
1443 
1444  // setup block
1445  $block = new Block( [
1446  'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
1447  ] );
1448  $block->setTarget( '1.2.3.4' );
1449  $block->setBlocker( $this->getTestSysop()->getUser() );
1450  $block->insert();
1451 
1452  // setup request
1453  $request = new FauxRequest();
1454  $request->setIP( '1.2.3.4' );
1455  $request->getSession()->setUser( $this->getTestUser()->getUser() );
1456  $request->setCookie( 'BlockID', $block->getCookieValue() );
1457 
1458  // setup user
1460 
1461  // logged in users should be inmune to cookie block of type ip/range
1462  $this->assertFalse( $user->isBlocked() );
1463 
1464  // cookie is being cleared
1465  $cookies = $request->response()->getCookies();
1466  $this->assertEquals( '', $cookies['wikiBlockID']['value'] );
1467 
1468  // clean up
1469  $block->delete();
1470  }
1471 
1477  $clock = MWTimestamp::convert( TS_UNIX, '20100101000000' );
1478  MWTimestamp::setFakeTime( function () use ( &$clock ) {
1479  return $clock += 1000;
1480  } );
1481  try {
1482  $user = $this->getTestUser()->getUser();
1483  $firstRevision = self::makeEdit( $user, 'Help:UserTest_GetEditTimestamp', 'one', 'test' );
1484  $secondRevision = self::makeEdit( $user, 'Help:UserTest_GetEditTimestamp', 'two', 'test' );
1485  // Sanity check: revisions timestamp are different
1486  $this->assertNotEquals( $firstRevision->getTimestamp(), $secondRevision->getTimestamp() );
1487 
1488  $this->assertEquals( $firstRevision->getTimestamp(), $user->getFirstEditTimestamp() );
1489  $this->assertEquals( $secondRevision->getTimestamp(), $user->getLatestEditTimestamp() );
1490  } finally {
1491  MWTimestamp::setFakeTime( false );
1492  }
1493  }
1494 
1502  private static function makeEdit( User $user, $title, $content, $comment ) {
1504  $content = ContentHandler::makeContent( $content, $page->getTitle() );
1505  $updater = $page->newPageUpdater( $user );
1506  $updater->setContent( 'main', $content );
1507  return $updater->saveRevision( CommentStoreComment::newUnsavedComment( $comment ) );
1508  }
1509 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:138
testGetGroupsWithPermission( $expected, $right)
provideGetGroupsWithPermission User::getGroupsWithPermission
Definition: UserTest.php:159
provideExperienceLevel()
Definition: UserTest.php:932
isHidden()
Check if user account is hidden.
Definition: User.php:2399
testIsIP( $value, $result, $message)
provideIPs User::isIP
Definition: UserTest.php:192
static getMainWANInstance()
Get the main WAN cache object.
testLoggedIn()
User::isLoggedIn User::isAnon.
Definition: UserTest.php:510
testGetId()
User::getId.
Definition: UserTest.php:501
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition: User.php:1725
User $user
Definition: UserTest.php:23
$wgDefaultUserOptions
Settings added to this array will override the default globals for the user preferences used by anony...
testRevokePermissions()
User::getGroupPermissions.
Definition: UserTest.php:87
static getGroupPermissions( $groups)
Get the permissions associated with a given list of groups.
Definition: User.php:5006
saveSettings()
Save this user&#39;s settings into the database.
Definition: User.php:4181
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
getFirstEditTimestamp()
Get the timestamp of the first edit.
Definition: User.php:4955
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
testExperienceLevelAnon()
User::getExperienceLevel.
Definition: UserTest.php:977
testUserPermissions()
User::getRights.
Definition: UserTest.php:98
getOption( $oname, $defaultOverride=null, $ignoreHidden=false)
Get the user&#39;s current setting for a given option.
Definition: User.php:3163
blockedBy()
If user is blocked, return the name of the user who placed the block.
Definition: User.php:2306
testCheckPasswordValidity()
Test password validity checks.
Definition: UserTest.php:371
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
getBlock( $fromReplica=true)
Get the block affecting the user, or null if the user is not blocked.
Definition: User.php:2280
getExperienceLevel()
Compute experienced level based on edit count and registration date.
Definition: User.php:4059
markTestSkippedIfDbType( $type)
Skip the test if using the specified database type.
$value
checkAndSetTouched()
Bump user_touched if it didn&#39;t change since this object was loaded.
Definition: User.php:1687
isLoggedIn()
Get whether the user is logged in.
Definition: User.php:3787
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object...
Definition: User.php:5637
mergeMwGlobalArrayValue( $name, $values)
Merges the given values into a MW global array variable.
testIsBlockedFrom( $title, $expect, array $options=[])
User::isBlockedFrom provideIsBlockedFrom.
Definition: UserTest.php:1239
getDBTouched()
Get the user_touched timestamp field (time of last DB updates)
Definition: User.php:2862
A helper class for throttling authentication attempts.
$wgRevokePermissions
Permission keys revoked from users in each group.
testIsPingLimitable()
User::isPingLimitable.
Definition: UserTest.php:910
static newFromActorId( $id)
Static factory method for creation from a given actor ID.
Definition: User.php:626
setOption( $oname, $val)
Set the given option for a user.
Definition: User.php:3250
testGetEditCountForAnons()
Test User::editCount medium User::getEditCount.
Definition: UserTest.php:286
static newUnsavedComment( $comment, array $data=null)
Create a new, unsaved CommentStoreComment.
isBlocked( $fromReplica=true)
Check if user is blocked.
Definition: User.php:2269
testIpBlockCookieNotSet()
Block cookie should NOT be set when wgCookieSetOnIpBlock is disabled User::trackBlockWithCookie.
Definition: UserTest.php:1400
const DB_MASTER
Definition: defines.php:26
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2443
static selectFields()
Return the list of user fields that should be selected to create a new user object.
Definition: User.php:5611
testIncEditCount()
Test User::editCount medium User::incEditCount.
Definition: UserTest.php:307
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1980
$wgGroupPermissions
Permission keys given to users in each group.
static findUsersByGroup( $groups, $limit=5000, $after=null)
Return the users who are members of the given group(s).
Definition: User.php:1079
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:48
static provideGetCanonicalName()
Definition: UserTest.php:455
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1982
static getCanonicalName( $name, $validate='valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid...
Definition: User.php:1246
testIpBlockCookieSet()
Block cookie should be set for IP Blocks if wgCookieSetOnIpBlock is set to true User::trackBlockWithC...
Definition: UserTest.php:1364
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
static getTestSysop()
Convenience method for getting an immutable admin test user.
static getMain()
Get the RequestContext object associated with the main request.
static provideIPs()
Definition: UserTest.php:196
const USER_TALK_PAGE
Constant for self::testIsBlockedFrom.
Definition: UserTest.php:18
testCheckAndSetTouched()
User::checkAndSetTouched.
Definition: UserTest.php:528
isValidPassword( $password)
Is the input a valid password for this user?
Definition: User.php:1149
static getGroupsWithPermission( $role)
Get all the groups who have a given permission.
Definition: User.php:5033
isAnon()
Get whether the user is anonymous.
Definition: User.php:3795
testIpBlockCookieIgnoredWhenUserLoggedIn()
When an ip user is blocked and then they log in, cookie block should be invalid and the cookie remove...
Definition: UserTest.php:1436
static isLocallyBlockedProxy( $ip)
Check if an IP address is in the local proxy list.
Definition: User.php:2052
static purge( $wikiId, $userId)
Definition: User.php:490
static getMutableTestUser( $groups=[])
Convenience method for getting a mutable test user.
$res
Definition: database.txt:21
testAutoblockCookies()
When a user is autoblocked a cookie is set with which to track them in case they log out and change I...
Definition: UserTest.php:588
load( $flags=self::READ_NORMAL)
Load the user table data for this object from the source given by mFrom.
Definition: User.php:360
equals(UserIdentity $user)
Checks if two user objects point to the same user.
Definition: User.php:5723
incEditCount()
Schedule a deferred update to update the user&#39;s edit count.
Definition: User.php:5344
testBlockInstanceCache()
User::getBlockedStatus User::getBlock User::blockedBy User::blockedFor User::isHidden User::isBlocked...
Definition: UserTest.php:1187
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same user
Wikitext formatted, in the key only.
Definition: distributors.txt:9
getLatestEditTimestamp()
Get the timestamp of the latest edit.
Definition: User.php:4966
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1982
testFindUsersByGroup()
User::findUsersByGroup.
Definition: UserTest.php:549
static provideUserNames()
Definition: UserTest.php:221
testGetFirstLatestEditTimestamp()
User::getFirstEditTimestamp User::getLatestEditTimestamp.
Definition: UserTest.php:1476
setUpPermissionGlobals()
Definition: UserTest.php:40
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format...
Definition: MWCryptRand.php:36
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
Value object representing a user&#39;s identity.
trackBlockWithCookie()
Set the &#39;BlockID&#39; cookie depending on block type and user authentication status.
Definition: User.php:1396
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
isBlockedFrom( $title, $fromReplica=false)
Check if user is blocked from editing a particular article.
Definition: User.php:2297
static makeEdit(User $user, $title, $content, $comment)
Definition: UserTest.php:1502
testIsLocallyBlockedProxy( $ip, $blockListEntry)
provideIsLocallBlockedProxy User::isLocallyBlockedProxy
Definition: UserTest.php:994
getPasswordValidity( $password)
Given unvalidated password input, return error message on failure.
Definition: User.php:1161
testAnonOptions()
T39963 Make sure defaults are loaded when setOption is called.
Definition: UserTest.php:355
static provideIsBlockedFrom()
Definition: UserTest.php:1282
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
testExperienceLevel( $editCount, $memberSince, $expLevel)
User::getExperienceLevel provideExperienceLevel.
Definition: UserTest.php:949
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown...
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition: User.php:654
const SCHEMA_COMPAT_WRITE_BOTH
Definition: Defines.php:288
hideDeprecated( $function)
Don&#39;t throw a warning if $function is deprecated and called later.
static TestUser [] $users
testNewFromIdentity()
User::newFromIdentity.
Definition: UserTest.php:1148
testGetCanonicalName( $name, $expectedArray)
User::getCanonicalName() provideGetCanonicalName.
Definition: UserTest.php:431
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:589
testSoftBlockRanges()
User::getBlockedStatus.
Definition: UserTest.php:779
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
static getIdFromCookieValue( $cookieValue)
Get the stored ID from the &#39;BlockID&#39; cookie.
Definition: Block.php:1845
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:780
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:611
static newFromAnyId( $userId, $userName, $actorId)
Static factory method for creation from an ID, name, and/or actor ID.
Definition: User.php:678
testAutoblockCookieNoSecretKey()
The BlockID cookie is normally verified with a HMAC, but not if wgSecretKey is not set...
Definition: UserTest.php:863
static getDummySession( $backend=null, $index=-1, $logger=null)
If you need a Session for testing but don&#39;t want to create a backend to construct one...
Definition: TestUtils.php:86
getId()
Get the user&#39;s ID.
Definition: User.php:2416
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
getActorId(IDatabase $dbw=null)
Get the user&#39;s actor ID.
Definition: User.php:2482
testAutoblockCookieInauthentic()
Test that a modified BlockID cookie doesn&#39;t actually load the relevant block (T152951).
Definition: UserTest.php:818
static newFromRow( $row, $data=null)
Create a new user object from a user row.
Definition: User.php:774
testGetEditCount()
Test User::editCount medium User::getEditCount.
Definition: UserTest.php:249
$page->newPageUpdater($user) $updater
Definition: pageupdater.txt:63
static newFromSession(WebRequest $request=null)
Create a new user object using data from session.
Definition: User.php:752
getEditCount()
Get the user&#39;s edit count.
Definition: User.php:3686
testUserGetRightsHooks()
User::getRights.
Definition: UserTest.php:109
const TYPE_USER
Definition: Block.php:96
getBlockId()
If user is blocked, return the ID for the block.
Definition: User.php:2324
Database $db
Primary database.
testIsValidUserName( $username, $result, $message)
provideUserNames User::isValidUserName
Definition: UserTest.php:217
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
testAutoblockCookiesDisabled()
Make sure that no cookie is set to track autoblocked users when $wgCookieSetOnAutoblock is false...
Definition: UserTest.php:669
static provideGetGroupsWithPermission()
Definition: UserTest.php:167
checkPasswordValidity( $password)
Check if this is a valid password for this user.
Definition: User.php:1204
const SCHEMA_COMPAT_READ_OLD
Definition: Defines.php:285
testAutoblockCookieInfiniteExpiry()
When a user is autoblocked and a cookie is set to track them, the expiry time of the cookie should ma...
Definition: UserTest.php:715
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition: User.php:4294
getExistingTestPage( $title=null)
Returns a WikiPage representing an existing page.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:587
testActorId()
User::newFromActorId.
Definition: UserTest.php:1032
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
$content
Definition: pageupdater.txt:72
const NS_USER_TALK
Definition: Defines.php:67
getTalkPage()
Get this user&#39;s talk page title.
Definition: User.php:4550
Definition: Block.php:31
isPingLimitable()
Is this user subject to rate limiting?
Definition: User.php:2098
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2633
testOptions()
Test changing user options.
Definition: UserTest.php:326
testGroupPermissions()
User::getGroupPermissions.
Definition: UserTest.php:70
testNewFromAnyId()
User::newFromAnyId.
Definition: UserTest.php:1098
static provideIsLocallBlockedProxy()
Definition: UserTest.php:983
Database.
Definition: UserTest.php:15
getRights()
Get the permissions this user has.
Definition: User.php:3541
blockedFor()
If user is blocked, return the specified reason for the block.
Definition: User.php:2315
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:319
testEquals()
User::equals.
Definition: UserTest.php:477