From b7221eaa0893e9e1ed31355e3ea98773fbc628ba Mon Sep 17 00:00:00 2001 From: WMDE-Fisch Date: Wed, 13 Apr 2016 17:52:48 +0200 Subject: [PATCH] Hide hiddencat catwatch changes in special changelists If a hidden category has a member added or removed this will only be shown to users that have the user preference "display hidden categories". Also added method to WikiCategoryPage to check for hidden status. Added unit tests for both. Bug: T127944 Change-Id: Ic53d51391fa29d5e18fef4c42b8a275816c7ba4a --- includes/PageProps.php | 27 ++++++++ includes/changes/RecentChange.php | 17 +++++- includes/page/WikiCategoryPage.php | 14 +++++ includes/page/WikiPage.php | 2 +- includes/specials/SpecialRecentchanges.php | 11 ++++ includes/specials/SpecialWatchlist.php | 11 ++++ .../includes/changes/RecentChangeTest.php | 47 ++++++++++++++ .../includes/page/WikiCategoryPageTest.php | 61 +++++++++++++++++++ 8 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 tests/phpunit/includes/page/WikiCategoryPageTest.php diff --git a/includes/PageProps.php b/includes/PageProps.php index bc3e3f1529..3654384722 100644 --- a/includes/PageProps.php +++ b/includes/PageProps.php @@ -33,6 +33,33 @@ class PageProps { */ private static $instance; + /** + * Overrides the default instance of this class + * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined. + * + * If this method is used it MUST also be called with null after a test to ensure a new + * default instance is created next time getInstance is called. + * + * @since 1.27 + * + * @param PageProps|null $store + * + * @return ScopedCallback to reset the overridden value + * @throws MWException + */ + public static function overrideInstance( PageProps $store = null ) { + if ( !defined( 'MW_PHPUNIT_TEST' ) ) { + throw new MWException( + 'Cannot override ' . __CLASS__ . 'default instance in operation.' + ); + } + $previousValue = self::$instance; + self::$instance = $store; + return new ScopedCallback( function() use ( $previousValue ) { + self::$instance = $previousValue; + } ); + } + /** * @return PageProps */ diff --git a/includes/changes/RecentChange.php b/includes/changes/RecentChange.php index 2508304ce1..6a901d0015 100644 --- a/includes/changes/RecentChange.php +++ b/includes/changes/RecentChange.php @@ -851,7 +851,9 @@ class RecentChange { 'rc_logid' => 0, 'rc_log_type' => null, 'rc_log_action' => '', - 'rc_params' => '' + 'rc_params' => serialize( [ + 'hidden-cat' => WikiCategoryPage::factory( $categoryTitle )->isHidden() + ] ) ]; $rc->mExtra = [ @@ -865,6 +867,19 @@ class RecentChange { return $rc; } + /** + * Get a parameter value + * + * @since 1.27 + * + * @param string $name parameter name + * @return mixed + */ + public function getParam( $name ) { + $params = $this->parseParams(); + return isset( $params[$name] ) ? $params[$name] : null; + } + /** * Initialises the members of this object from a mysql row object * diff --git a/includes/page/WikiCategoryPage.php b/includes/page/WikiCategoryPage.php index d38200169b..6c932029ae 100644 --- a/includes/page/WikiCategoryPage.php +++ b/includes/page/WikiCategoryPage.php @@ -47,4 +47,18 @@ class WikiCategoryPage extends WikiPage { } return false; } + + /** + * Checks if a category is hidden. + * + * @since 1.27 + * + * @return bool + */ + public function isHidden() { + $pageId = $this->getTitle()->getArticleID(); + $pageProps = PageProps::getInstance()->getProperties( $this->getTitle(), 'hiddencat' ); + + return isset( $pageProps[$pageId] ) ? true : false; + } } diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 82e66aa223..06785b70e3 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -94,7 +94,7 @@ class WikiPage implements Page, IDBAccessObject { * @param Title $title * * @throws MWException - * @return WikiPage Object of the appropriate type + * @return WikiPage|WikiCategoryPage|WikiFilePage */ public static function factory( Title $title ) { $ns = $title->getNamespace(); diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php index de773800ac..8e52f14aef 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -324,12 +324,23 @@ class SpecialRecentChanges extends ChangesListSpecialPage { $list = ChangesList::newFromContext( $this->getContext() ); $list->initChangesListRows( $rows ); + $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' ); $rclistOutput = $list->beginRecentChangesList(); foreach ( $rows as $obj ) { if ( $limit == 0 ) { break; } $rc = RecentChange::newFromRow( $obj ); + + # Skip CatWatch entries for hidden cats based on user preference + if ( + $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE && + !$userShowHiddenCats && + $rc->getParam( 'hidden-cat' ) + ) { + continue; + } + $rc->counter = $counter++; # Check if the page has been updated since the last visit if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index 27e5829560..15691f2c46 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -369,10 +369,21 @@ class SpecialWatchlist extends ChangesListSpecialPage { } $s = $list->beginRecentChangesList(); + $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' ); $counter = 1; foreach ( $rows as $obj ) { # Make RC entry $rc = RecentChange::newFromRow( $obj ); + + # Skip CatWatch entries for hidden cats based on user preference + if ( + $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE && + !$userShowHiddenCats && + $rc->getParam( 'hidden-cat' ) + ) { + continue; + } + $rc->counter = $counter++; if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) ) { diff --git a/tests/phpunit/includes/changes/RecentChangeTest.php b/tests/phpunit/includes/changes/RecentChangeTest.php index 4abe9eef6a..2efc802cda 100644 --- a/tests/phpunit/includes/changes/RecentChangeTest.php +++ b/tests/phpunit/includes/changes/RecentChangeTest.php @@ -134,4 +134,51 @@ class RecentChangeTest extends MediaWikiTestCase { $this->assertEquals( $rcType, RecentChange::parseToRCType( $type ) ); } + /** + * @return PHPUnit_Framework_MockObject_MockObject|PageProps + */ + private function getMockPageProps() { + return $this->getMockBuilder( PageProps::class ) + ->disableOriginalConstructor() + ->getMock(); + } + + public function provideCategoryContent() { + return [ + [ true ], + [ false ], + ]; + } + + /** + * @dataProvider provideCategoryContent + * @covers RecentChange::newForCategorization + */ + public function testHiddenCategoryChange( $isHidden ) { + $categoryTitle = Title::newFromText( 'CategoryPage', NS_CATEGORY ); + + $pageProps = $this->getMockPageProps(); + $pageProps->expects( $this->once() ) + ->method( 'getProperties' ) + ->with( $categoryTitle, 'hiddencat' ) + ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [ ] ) ); + + $scopedOverride = PageProps::overrideInstance( $pageProps ); + + $rc = RecentChange::newForCategorization( + '0', + $categoryTitle, + $this->user, + $this->user_comment, + $this->title, + $categoryTitle->getLatestRevID(), + $categoryTitle->getLatestRevID(), + '0', + false + ); + + $this->assertEquals( $isHidden, $rc->getParam( 'hidden-cat' ) ); + + ScopedCallback::consume( $scopedOverride ); + } } diff --git a/tests/phpunit/includes/page/WikiCategoryPageTest.php b/tests/phpunit/includes/page/WikiCategoryPageTest.php new file mode 100644 index 0000000000..d6e1d9e0b8 --- /dev/null +++ b/tests/phpunit/includes/page/WikiCategoryPageTest.php @@ -0,0 +1,61 @@ +getMockBuilder( PageProps::class ) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @covers WikiCategoryPage::isHidden + */ + public function testHiddenCategory_PropertyNotSet() { + $title = Title::makeTitle( NS_CATEGORY, 'CategoryPage' ); + $categoryPage = WikiCategoryPage::factory( $title ); + + $pageProps = $this->getMockPageProps(); + $pageProps->expects( $this->once() ) + ->method( 'getProperties' ) + ->with( $title, 'hiddencat' ) + ->will( $this->returnValue( [ ] ) ); + + $scopedOverride = PageProps::overrideInstance( $pageProps ); + + $this->assertFalse( $categoryPage->isHidden() ); + + ScopedCallback::consume( $scopedOverride ); + } + + public function provideCategoryContent() { + return [ + [ true ], + [ false ], + ]; + } + + /** + * @dataProvider provideCategoryContent + * @covers WikiCategoryPage::isHidden + */ + public function testHiddenCategory_PropertyIsSet( $isHidden ) { + $categoryTitle = Title::makeTitle( NS_CATEGORY, 'CategoryPage' ); + $categoryPage = WikiCategoryPage::factory( $categoryTitle ); + + $pageProps = $this->getMockPageProps(); + $pageProps->expects( $this->once() ) + ->method( 'getProperties' ) + ->with( $categoryTitle, 'hiddencat' ) + ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [ ] ) ); + + $scopedOverride = PageProps::overrideInstance( $pageProps ); + + $this->assertEquals( $isHidden, $categoryPage->isHidden() ); + + ScopedCallback::consume( $scopedOverride ); + } +} -- 2.20.1