User: Fully clear instance variables when loading not-blocked status
authorBrad Jorsch <bjorsch@wikimedia.org>
Thu, 22 Mar 2018 16:52:59 +0000 (12:52 -0400)
committerBrad Jorsch <bjorsch@wikimedia.org>
Thu, 22 Mar 2018 19:01:28 +0000 (15:01 -0400)
If a block is deleted and ->clearInstanceCache() is called to try to
make an existing User object reflect that fact, some methods are still
reflecting the old block.

To fix this, User::getBlockedStatus() needs to clear all the relevant
instance variables if the user is found not to be blocked.

Change-Id: I6ad8d5555a4c8519336aded3067e5034831dadf3

includes/user/User.php
tests/phpunit/includes/user/UserTest.php

index d6523a7..47d7533 100644 (file)
@@ -1871,7 +1871,9 @@ class User implements IDBAccessObject, UserIdentity {
                        $this->mHideName = $block->mHideName;
                        $this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
                } else {
+                       $this->mBlock = null;
                        $this->mBlockedby = '';
+                       $this->mBlockreason = '';
                        $this->mHideName = 0;
                        $this->mAllowUsertalk = false;
                }
index c225ba5..ca83d66 100644 (file)
@@ -1142,4 +1142,55 @@ class UserTest extends MediaWikiTestCase {
                } catch ( InvalidArgumentException $ex ) {
                }
        }
+
+       /**
+        * @covers User::getBlockedStatus
+        * @covers User::getBlock
+        * @covers User::blockedBy
+        * @covers User::blockedFor
+        * @covers User::isHidden
+        * @covers User::isBlockedFrom
+        */
+       public function testBlockInstanceCache() {
+               // First, check the user isn't blocked
+               $user = $this->getMutableTestUser()->getUser();
+               $ut = Title::makeTitle( NS_USER_TALK, $user->getName() );
+               $this->assertNull( $user->getBlock( false ), 'sanity check' );
+               $this->assertSame( '', $user->blockedBy(), 'sanity check' );
+               $this->assertSame( '', $user->blockedFor(), 'sanity check' );
+               $this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
+               $this->assertFalse( $user->isBlockedFrom( $ut ), 'sanity check' );
+
+               // Block the user
+               $blocker = $this->getTestSysop()->getUser();
+               $block = new Block( [
+                       'hideName' => true,
+                       'allowUsertalk' => false,
+                       'reason' => 'Because',
+               ] );
+               $block->setTarget( $user );
+               $block->setBlocker( $blocker );
+               $res = $block->insert();
+               $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
+
+               // Clear cache and confirm it loaded the block properly
+               $user->clearInstanceCache();
+               $this->assertInstanceOf( Block::class, $user->getBlock( false ) );
+               $this->assertSame( $blocker->getName(), $user->blockedBy() );
+               $this->assertSame( 'Because', $user->blockedFor() );
+               $this->assertTrue( (bool)$user->isHidden() );
+               $this->assertTrue( $user->isBlockedFrom( $ut ) );
+
+               // Unblock
+               $block->delete();
+
+               // Clear cache and confirm it loaded the not-blocked properly
+               $user->clearInstanceCache();
+               $this->assertNull( $user->getBlock( false ) );
+               $this->assertSame( '', $user->blockedBy() );
+               $this->assertSame( '', $user->blockedFor() );
+               $this->assertFalse( (bool)$user->isHidden() );
+               $this->assertFalse( $user->isBlockedFrom( $ut ) );
+       }
+
 }