From f81bb12266ce27e4dc0c4d535333d5a1f71152c1 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 30 Mar 2016 22:05:25 +0200 Subject: [PATCH] Allow to define exceptions for Special:UncategorizedCategories on-wiki The new system message uncategorized-categories-exceptionlist can be changed on-wiki to hold a list of categories, that shouldn't be visible on the special page Special:UncategorizedCategories (with a trailing "* "), even if these categories aren't in any category. Bug: T126117 Change-Id: I65989e40f3caa2fad7b8b35109c0466e01084f72 --- .../SpecialUncategorizedcategories.php | 43 +++++++++++++ languages/i18n/en.json | 1 + languages/i18n/qqq.json | 1 + .../SpecialUncategorizedcategoriesTest.php | 62 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 tests/phpunit/includes/specials/SpecialUncategorizedcategoriesTest.php diff --git a/includes/specials/SpecialUncategorizedcategories.php b/includes/specials/SpecialUncategorizedcategories.php index 86d8f89c52..7c3265d625 100644 --- a/includes/specials/SpecialUncategorizedcategories.php +++ b/includes/specials/SpecialUncategorizedcategories.php @@ -27,11 +27,54 @@ * @ingroup SpecialPage */ class UncategorizedCategoriesPage extends UncategorizedPagesPage { + /** + * Holds a list of categories, which shouldn't be listed on this special page, + * even if it is uncategorized. + * @var array + */ + private $exceptionList = null; + function __construct( $name = 'Uncategorizedcategories' ) { parent::__construct( $name ); $this->requestedNamespace = NS_CATEGORY; } + /** + * Returns an array of categorie titles (usually without the namespace), which + * shouldn't be listed on this page, even if they're uncategorized. + * + * @return array + */ + private function getExceptionList() { + if ( $this->exceptionList === null ) { + $exList = $this->msg( 'uncategorized-categories-exceptionlist' ) + ->inContentLanguage()->plain(); + $proposedTitles = explode( "\n", $exList ); + foreach ( $proposedTitles as $count => $title ) { + if ( strpos( $title, '*' ) !== 0 ) { + continue; + } + $title = preg_replace( "/^\\*\\s*/", '', $title ); + $title = Title::newFromText( $title, NS_CATEGORY ); + if ( $title ) { + $this->exceptionList[] = $title->getDBKey(); + } + } + } + return $this->exceptionList; + } + + public function getQueryInfo() { + $dbr = wfGetDB( DB_SLAVE ); + $query = parent::getQueryInfo(); + $exceptionList = $this->getExceptionList(); + if ( $exceptionList ) { + $query['conds'][] = 'page_title not in ( ' . $dbr->makeList( $exceptionList ) . ' )'; + } + + return $query; + } + /** * Formats the result * @param Skin $skin The current skin diff --git a/languages/i18n/en.json b/languages/i18n/en.json index a621f1c5b2..a53b2cce2d 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1815,6 +1815,7 @@ "uncategorizedimages-summary": "", "uncategorizedtemplates": "Uncategorized templates", "uncategorizedtemplates-summary": "", + "uncategorized-categories-exceptionlist": " # Contains a list of catgeories, which shouldn't be mentioned on Special:UncategorizedCategories. One per line, starting with \"*\". Lines starting with another character (including whitespaces) are ignored. Use \"#\" for comments.", "unusedcategories": "Unused categories", "unusedcategories-summary": "", "unusedimages": "Unused files", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index da43aef239..eee9b4e1d5 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -2000,6 +2000,7 @@ "uncategorizedimages-summary": "{{notranslate}}\nused in [[Special:Uncategorizedimages]]. [[mw:Manual:Interface/Special pages summary|mw manual]].", "uncategorizedtemplates": "{{doc-special|UncategorizedTemplates}}", "uncategorizedtemplates-summary": "{{doc-specialpagesummary|uncategorizedtemplates}}", + "uncategorized-categories-exceptionlist": "System message used as a list of exceptions for Special:UncategorizedCategories. {{notranslate}}", "unusedcategories": "{{doc-special|UnusedCategories}}", "unusedcategories-summary": "{{doc-specialpagesummary|unusedcategories}}", "unusedimages": "{{doc-special|UnusedImages}}", diff --git a/tests/phpunit/includes/specials/SpecialUncategorizedcategoriesTest.php b/tests/phpunit/includes/specials/SpecialUncategorizedcategoriesTest.php new file mode 100644 index 0000000000..64e78f2828 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialUncategorizedcategoriesTest.php @@ -0,0 +1,62 @@ +getMockBuilder( 'RequestContext' )->getMock(); + $mockContext->method( 'msg' )->willReturn( $msg ); + $special = new UncategorizedCategoriesPage(); + $special->setContext( $mockContext ); + $this->assertEquals( [ + 'tables' => [ + 0 => 'page', + 1 => 'categorylinks', + ], + 'fields' => [ + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'page_title', + ], + 'conds' => [ + 0 => 'cl_from IS NULL', + 'page_namespace' => 14, + 'page_is_redirect' => 0, + ] + $expected, + 'join_conds' => [ + 'categorylinks' => [ + 0 => 'LEFT JOIN', + 1 => 'cl_from = page_id', + ], + ], + ], $special->getQueryInfo() ); + } + + public function provideTestGetQueryInfoData() { + return [ + [ + "* Stubs\n* Test\n* *\n* * test123", + [ 1 => "page_title not in ( 'Stubs','Test','*','*_test123' )" ] + ], + [ + "Stubs\n* Test\n* *\n* * test123", + [ 1 => "page_title not in ( 'Test','*','*_test123' )" ] + ], + [ + "* StubsTest\n* *\n* * test123", + [ 1 => "page_title not in ( 'StubsTest','*','*_test123' )" ] + ], + [ "", [] ], + [ "\n\n\n", [] ], + [ "\n", [] ], + [ "Test\n*Test2", [ 1 => "page_title not in ( 'Test2' )" ] ], + [ "Test", [] ], + [ "*Test\nTest2", [ 1 => "page_title not in ( 'Test' )" ] ], + [ "Test\nTest2", [] ], + ]; + } +} -- 2.20.1