WikidataBuilder has uploaded a new change for review. https://gerrit.wikimedia.org/r/266478
Change subject: New Wikidata Build - 2016-01-26T10:00:01+0000 ...................................................................... New Wikidata Build - 2016-01-26T10:00:01+0000 Change-Id: I2f1b16ff103dba876493aa72f16a2d33f3f80879 --- M composer.lock M extensions/Wikibase/README.md M extensions/Wikibase/client/i18n/tt-cyrl.json M extensions/Wikibase/client/includes/Hooks/OtherProjectsSidebarGenerator.php M extensions/Wikibase/client/includes/LangLinkHandler.php M extensions/Wikibase/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php M extensions/Wikibase/docs/hooks.txt A extensions/Wikibase/docs/public-apis.wiki M extensions/Wikibase/lib/i18n/de.json M extensions/Wikibase/lib/i18n/en.json M extensions/Wikibase/lib/i18n/zh-hant.json M extensions/Wikibase/lib/tests/phpunit/EntityRevisionLookupTest.php M extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeTest.php M extensions/Wikibase/repo/Wikibase.hooks.php M extensions/Wikibase/repo/i18n/el.json M extensions/Wikibase/repo/i18n/gd.json M extensions/Wikibase/repo/i18n/zh-hans.json M extensions/Wikibase/repo/includes/EditEntity.php M extensions/Wikibase/repo/includes/EditEntityFactory.php M extensions/Wikibase/repo/includes/Hooks/EditFilterHookRunner.php M extensions/Wikibase/repo/tests/phpunit/includes/ParserOutput/PageImagesDataUpdaterTest.php M extensions/Wikibase/repo/tests/phpunit/includes/store/sql/EntityPerPageBuilderTest.php M extensions/Wikibase/view/src/EntityTermsView.php M extensions/Wikibase/view/src/EntityViewPlaceholderExpander.php M extensions/Wikibase/view/tests/phpunit/EntityTermsViewTest.php M extensions/WikimediaBadges/WikimediaBadges.php M extensions/WikimediaBadges/composer.json R extensions/WikimediaBadges/includes/BeforePageDisplayHookHandler.php A extensions/WikimediaBadges/includes/OtherProjectsSidebarHookHandler.php A extensions/WikimediaBadges/tests/phpunit/includes/BeforePageDisplayHookHandlerTest.php A extensions/WikimediaBadges/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php M vendor/composer/autoload_classmap.php M vendor/composer/autoload_psr4.php M vendor/composer/installed.json 34 files changed, 863 insertions(+), 111 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata refs/changes/78/266478/1 diff --git a/composer.lock b/composer.lock index 44ae127..824c25e 100644 --- a/composer.lock +++ b/composer.lock @@ -1449,12 +1449,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd" + "reference": "53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd", - "reference": "b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9", + "reference": "53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9", "shasum": "" }, "require": { @@ -1525,7 +1525,7 @@ "wikibaserepo", "wikidata" ], - "time": "2016-01-21 03:04:33" + "time": "2016-01-26 09:44:07" }, { "name": "wikibase/wikimedia-badges", @@ -1533,7 +1533,7 @@ "source": { "type": "git", "url": "https://gerrit.wikimedia.org/r/mediawiki/extensions/WikimediaBadges", - "reference": "22cfee80965d12162f97405d38ed8ec32f56e59c" + "reference": "885441b2e0f3cab5f8b5731cf22581309dee2735" }, "require": { "php": ">=5.3.0" @@ -1543,9 +1543,9 @@ "files": [ "WikimediaBadges.php" ], - "classmap": [ - "WikimediaBadges.hooks.php" - ] + "psr-4": { + "WikimediaBadges\\": "includes/" + } }, "license": [ "GNU GPL v2+" @@ -1567,7 +1567,7 @@ "support": { "irc": "irc://irc.freenode.net/wikidata" }, - "time": "2016-01-18 13:08:32" + "time": "2016-01-21 13:15:32" } ], "packages-dev": [], diff --git a/extensions/Wikibase/README.md b/extensions/Wikibase/README.md index 6a9cf38..51147d3 100644 --- a/extensions/Wikibase/README.md +++ b/extensions/Wikibase/README.md @@ -26,8 +26,6 @@ The lib bundles common code that is used by both the client and the repo. -Note that in each of the directories you will also find `README.md` notes for each of the extensions. - ## Install This package contains three interrelated MediaWiki extensions: diff --git a/extensions/Wikibase/client/i18n/tt-cyrl.json b/extensions/Wikibase/client/i18n/tt-cyrl.json index 1aa7fcd..7f54ec5 100644 --- a/extensions/Wikibase/client/i18n/tt-cyrl.json +++ b/extensions/Wikibase/client/i18n/tt-cyrl.json @@ -29,6 +29,10 @@ "wikibase-rc-wikibase-edit-title": "{{WBREPONAME}} үзгәртүе", "wikibase-watchlist-show-changes-pref": "{{WBREPONAME}} булган үзгәртүләрне күзәтү исемлегендә карау", "wikibase-unconnectedpages-submit": "Битләрне күрсәтү", + "pageswithbadges": "Билгеле битләр", + "wikibase-pageswithbadges-badge": "Билге:", + "wikibase-pageswithbadges-submit": "Битләрне күрсәтү", + "wikibase-pageinfo-entity-id": "{{grammar:genitive|{{WBREPONAME}}}} ID элементы", "wikibase-pageinfo-entity-id-none": "Юк", "wikibase-otherprojects": "Башка проектларда", "wikibase-otherprojects-beta-message": "Башка проектлар өлгесе", diff --git a/extensions/Wikibase/client/includes/Hooks/OtherProjectsSidebarGenerator.php b/extensions/Wikibase/client/includes/Hooks/OtherProjectsSidebarGenerator.php index 85b8a62..285bbb5 100644 --- a/extensions/Wikibase/client/includes/Hooks/OtherProjectsSidebarGenerator.php +++ b/extensions/Wikibase/client/includes/Hooks/OtherProjectsSidebarGenerator.php @@ -2,10 +2,12 @@ namespace Wikibase\Client\Hooks; +use Hooks; use Site; use SiteStore; use Title; use Wikibase\DataModel\SiteLink; +use Wikibase\DataModel\Entity\ItemId; use Wikibase\Lib\Store\SiteLinkLookup; /** @@ -64,16 +66,74 @@ * group and global ids. */ public function buildProjectLinkSidebar( Title $title ) { - return $this->buildSidebarFromSiteLinks( $this->getSiteLinks( $title ) ); + $itemId = $this->getItemId( $title ); + if ( !$itemId ) { + return array(); + } + + $sidebar = $this->buildPreliminarySidebarFromSiteLinks( $this->getSiteLinks( $itemId ) ); + $sidebar = $this->runHook( $itemId, $sidebar ); + + return $this->sortAndFlattenSidebar( $sidebar ); + } + + /** + * @param ItemId $itemId + * @param array $sidebar + * + * @return array + */ + private function runHook( ItemId $itemId, array $sidebar ) { + $newSidebar = $sidebar; + + Hooks::run( 'WikibaseClientOtherProjectsSidebar', array( $itemId, &$newSidebar ) ); + + if ( $newSidebar === $sidebar ) { + return $sidebar; + } + + if ( !is_array( $newSidebar ) || !$this->isValidSidebar( $newSidebar ) ) { + wfLogWarning( 'Other projects sidebar data invalid after hook run.' ); + return $sidebar; + } + + return $newSidebar; + } + + /** + * @param array $sidebar + * @return bool + */ + private function isValidSidebar( array $sidebar ) { + // Make sure all required array keys are set and are string. + foreach ( $sidebar as $siteGroup => $perSiteGroup ) { + if ( !is_string( $siteGroup ) || !is_array( $perSiteGroup ) ) { + return false; + } + + foreach ( $perSiteGroup as $siteId => $perSite ) { + if ( !is_string( $siteId ) + || !isset( $perSite['msg'] ) + || !isset( $perSite['class'] ) + || !isset( $perSite['href'] ) + || !is_string( $perSite['msg'] ) + || !is_string( $perSite['class'] ) + || !is_string( $perSite['href'] ) + ) { + return false; + } + } + } + + return true; } /** * @param SiteLink[] $siteLinks * - * @return array[] Array of arrays of attributes describing sidebar links, sorted by the site's - * group and global ids. + * @return array[] Arrays of link attributes indexed by site group and by global site id. */ - private function buildSidebarFromSiteLinks( array $siteLinks ) { + private function buildPreliminarySidebarFromSiteLinks( array $siteLinks ) { $linksByGroup = array(); foreach ( $siteLinks as $siteLink ) { @@ -91,7 +151,7 @@ } } - return $this->sortAndFlattenSidebar( $linksByGroup ); + return $linksByGroup; } /** @@ -117,22 +177,25 @@ } /** - * @param Title $title + * @param ItemId $itemId * * @return SiteLink[] */ - private function getSiteLinks( Title $title ) { - $siteLink = new SiteLink( $this->localSiteId, $title->getFullText() ); - $itemId = $this->siteLinkLookup->getItemIdForSiteLink( $siteLink ); - - if ( $itemId === null ) { - return array(); - } - + private function getSiteLinks( ItemId $itemId ) { return $this->siteLinkLookup->getSiteLinksForItem( $itemId ); } /** + * @param Title $title + * + * @return Item|null + */ + private function getItemId( Title $title ) { + $siteLink = new SiteLink( $this->localSiteId, $title->getFullText() ); + return $this->siteLinkLookup->getItemIdForSiteLink( $siteLink ); + } + + /** * @param SiteLink $siteLink * @param Site $site * diff --git a/extensions/Wikibase/client/includes/LangLinkHandler.php b/extensions/Wikibase/client/includes/LangLinkHandler.php index ca4112d..335b0f1 100644 --- a/extensions/Wikibase/client/includes/LangLinkHandler.php +++ b/extensions/Wikibase/client/includes/LangLinkHandler.php @@ -115,7 +115,7 @@ $links = iterator_to_array( $item->getSiteLinkList() ); $links = $this->indexLinksBySiteId( $links ); } else { - wfWarn( __METHOD__ . ": Could not load item " . $itemId->getSerialization() + wfLogWarning( __METHOD__ . ": Could not load item " . $itemId->getSerialization() . " for " . $title->getFullText() ); } } diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php index b121789..f92a9fb 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php @@ -85,6 +85,187 @@ } /** + * @dataProvider projectLinkSidebarHookProvider + */ + public function testBuildProjectLinkSidebar_hook( + /* callable */ $handler, + array $siteIdsToOutput, + array $result, + $suppressErrors = false + ) { + $this->setMwGlobals( 'wgHooks', array( 'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) ); + + $otherProjectSidebarGenerator = new OtherProjectsSidebarGenerator( + 'enwiki', + $this->getSiteLinkLookup(), + $this->getSiteStore(), + $siteIdsToOutput + ); + + if ( $suppressErrors ) { + \MediaWiki\suppressWarnings(); + } + $this->assertEquals( + $result, + $otherProjectSidebarGenerator->buildProjectLinkSidebar( Title::makeTitle( NS_MAIN, 'Nyan Cat' ) ) + ); + + if ( $suppressErrors ) { + \MediaWiki\restoreWarnings(); + } + } + + public function projectLinkSidebarHookProvider() { + $wiktionaryLink = array( + 'msg' => 'wikibase-otherprojects-wiktionary', + 'class' => 'wb-otherproject-link wb-otherproject-wiktionary', + 'href' => 'https://en.wiktionary.org/wiki/Nyan_Cat', + 'hreflang' => 'en' + ); + $wikiquoteLink = array( + 'msg' => 'wikibase-otherprojects-wikiquote', + 'class' => 'wb-otherproject-link wb-otherproject-wikiquote', + 'href' => 'https://en.wikiquote.org/wiki/Nyan_Cat', + 'hreflang' => 'en' + ); + $wikipediaLink = array( + 'msg' => 'wikibase-otherprojects-wikipedia', + 'class' => 'wb-otherproject-link wb-otherproject-wikipedia', + 'href' => 'https://en.wikipedia.org/wiki/Nyan_Cat', + 'hreflang' => 'en' + ); + $changedWikipedaLink = array( + 'msg' => 'wikibase-otherprojects-wikipedia', + 'class' => 'wb-otherproject-link wb-otherproject-wikipedia', + 'href' => 'https://en.wikipedia.org/wiki/Cat', + 'hreflang' => 'en' + ); + $self = $this; // PHP 5.3 :( + + return array( + 'Noop hook, gets the right data' => array( + function( ItemId $itemId, array &$sidebar ) use ( $wikipediaLink, $wikiquoteLink, $wiktionaryLink, $self ) { + $self->assertSame( + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'wikipedia' => array( 'enwiki' => $wikipediaLink ), + 'wiktionary' => array( 'enwiktionary' => $wiktionaryLink ) + ), + $sidebar + ); + $self->assertSame( 'Q123', $itemId->getSerialization() ); + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $wikipediaLink, $wikiquoteLink, $wiktionaryLink ) + ), + 'Hook changes enwiki link' => array( + function( ItemId $itemId, array &$sidebar ) use ( $changedWikipedaLink ) { + $sidebar['wikipedia']['enwiki']['href'] = $changedWikipedaLink['href']; + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $changedWikipedaLink, $wikiquoteLink, $wiktionaryLink ) + ), + 'Hook inserts enwiki link' => array( + function( ItemId $itemId, array &$sidebar ) use ( $changedWikipedaLink, $self ) { + $self->assertFalse( + isset( $sidebar['wikipedia'] ), + 'No Wikipedia link present yet' + ); + + $sidebar['wikipedia']['enwiki'] = $changedWikipedaLink; + }, + array( 'enwiktionary', 'enwikiquote' ), + array( $changedWikipedaLink, $wikiquoteLink, $wiktionaryLink ) + ), + 'Invalid hook #1, original data is being used' => array( + function( ItemId $itemId, array &$sidebar ) { + $sidebar = null; + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $wikipediaLink, $wikiquoteLink, $wiktionaryLink ), + true + ), + 'Invalid hook #2, original data is being used' => array( + function( ItemId $itemId, array &$sidebar ) { + $sidebar[0]['msg'] = array(); + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $wikipediaLink, $wikiquoteLink, $wiktionaryLink ), + true + ), + 'Invalid hook #3, original data is being used' => array( + function( ItemId $itemId, array &$sidebar ) use ( $changedWikipedaLink ) { + $sidebar['wikipedia']['enwiki']['href'] = 1.2; + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $wikipediaLink, $wikiquoteLink, $wiktionaryLink ), + true + ), + 'Invalid hook #4, original data is being used' => array( + function( ItemId $itemId, array &$sidebar ) use ( $changedWikipedaLink ) { + $sidebar['wikipedia'][] = $changedWikipedaLink; + }, + array( 'enwiktionary', 'enwiki', 'enwikiquote' ), + array( $wikipediaLink, $wikiquoteLink, $wiktionaryLink ), + true + ), + ); + } + + public function testBuildProjectLinkSidebar_hookNotCalledIfPageNotConnected() { + $self = $this; // We all love PHP 5.3 + + $handler = function() use ( $self ) { + $self->assertTrue( false, "Should not get called." ); + }; + + $this->setMwGlobals( 'wgHooks', array( 'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) ); + + $lookup = $this->getMock( 'Wikibase\Lib\Store\SiteLinkLookup' ); + $lookup->expects( $this->any() ) + ->method( 'getItemIdForSiteLink' ) + ->will( $this->returnValue( null ) ); + + $otherProjectSidebarGenerator = new OtherProjectsSidebarGenerator( + 'enwiki', + $lookup, + $this->getSiteStore(), + array( 'enwiki' ) + ); + + $this->assertSame( + array(), + $otherProjectSidebarGenerator->buildProjectLinkSidebar( Title::makeTitle( NS_MAIN, 'Nyan Cat' ) ) + ); + } + + public function testBuildProjectLinkSidebar_hookCalledWithEmptySidebar() { + $self = $this; // We all love PHP 5.3 + $called = false; + + $handler = function( ItemId $itemId, $sidebar ) use ( $self, &$called ) { + $self->assertSame( 'Q123', $itemId->getSerialization() ); + $self->assertSame( array(), $sidebar ); + $called = true; + }; + + $this->setMwGlobals( 'wgHooks', array( 'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) ); + + $otherProjectSidebarGenerator = new OtherProjectsSidebarGenerator( + 'enwiki', + $this->getSiteLinkLookup(), + $this->getSiteStore(), + array( 'unknown-site' ) + ); + + $this->assertSame( + array(), + $otherProjectSidebarGenerator->buildProjectLinkSidebar( Title::makeTitle( NS_MAIN, 'Nyan Cat' ) ) + ); + $this->assertTrue( $called, 'Hook needs to be called' ); + } + + /** * @return SiteStore */ private function getSiteStore() { diff --git a/extensions/Wikibase/docs/hooks.txt b/extensions/Wikibase/docs/hooks.txt index 92e76fe..9b51cde 100644 --- a/extensions/Wikibase/docs/hooks.txt +++ b/extensions/Wikibase/docs/hooks.txt @@ -38,10 +38,18 @@ &$dataTypeDefinitions: the array of data type definitions, as defined by WikibaseClient.datatypes.php. Hook handlers may add additional definitions. See the datatypes.wiki file for details. -'WikibaseHandleChanges': Callend by ChangeHandler::handleChange() to allow pre-processing +'WikibaseHandleChanges': Called by ChangeHandler::handleChange() to allow pre-processing of changes. $changes: A list of Change objects -'WikibaseHandleChange': Callend by ChangeHandler::handleChange() to allow alternative +'WikibaseHandleChange': Called by ChangeHandler::handleChange() to allow alternative processing of changes. $change: A Change object + +'WikibaseClientOtherProjectsSidebar' Called by OtherProjectsSidebarGenerator to allow altering +the other projects sidebar. Only called in case the page we're on is linked with an item. +$itemId: Id of the item the page is linked with. +&$newSidedbar: Array containing the sidebar definition. The array consits of arrays indexed by +site groups containing arrays indexed by site id. These arrays represent the link to the given +site. They contain the keys "msg", "href" and "class" which contain the respective attributes +for the link that is going to be created. diff --git a/extensions/Wikibase/docs/public-apis.wiki b/extensions/Wikibase/docs/public-apis.wiki new file mode 100644 index 0000000..222fcbe --- /dev/null +++ b/extensions/Wikibase/docs/public-apis.wiki @@ -0,0 +1,15 @@ +The current status is that this extensions PHP interfaces may not be used by +other extensions. None of the PHP APIs have any stability guarantees. An +exception are extensions that fully cover these usages with unit tests which +are run by the CI pre-merge and are integrated in the Wikidata build. + +TODO: + +Explain how this extension can be used by other Mediawiki exstension, +which type of public APIs there are (HTTP API, Mediawiki hooks, composer +components, PHP classes, etc) and what stability guarantees are available and +how these are annotated on the individual parts (e.g. class level docs). + +See also: +* https://phabricator.wikimedia.org/T103070 Find extensions using code directly + from Wikibase and provide mechanism with a stable interface diff --git a/extensions/Wikibase/lib/i18n/de.json b/extensions/Wikibase/lib/i18n/de.json index 16857c1..d466563 100644 --- a/extensions/Wikibase/lib/i18n/de.json +++ b/extensions/Wikibase/lib/i18n/de.json @@ -83,13 +83,13 @@ "version-wikibase": "Wikibase-Erweiterungen", "wikibase-time-precision-Gannum": "$1 Milliarden Jahre n. Chr.", "wikibase-time-precision-Mannum": "$1 Millionen Jahre n. Chr.", - "wikibase-time-precision-annum": "$1 Jahre n. Chr.", + "wikibase-time-precision-annum": "{{PLURAL:$1|Ein Jahr|$1 Jahre}} n. Chr.", "wikibase-time-precision-millennium": "$1. Jahrtausend", "wikibase-time-precision-century": "$1. Jahrhundert", "wikibase-time-precision-10annum": "$1 Jahrzehnte", "wikibase-time-precision-BCE-Gannum": "$1 Milliarden Jahre v. Chr.", "wikibase-time-precision-BCE-Mannum": "$1 Millionen Jahre v. Chr.", - "wikibase-time-precision-BCE-annum": "$1 Jahre v. Chr.", + "wikibase-time-precision-BCE-annum": "{{PLURAL:$1|Ein Jahr|$1 Jahre}} v. Chr.", "wikibase-time-precision-BCE-millennium": "$1. Jahrtausend v. u. Z.", "wikibase-time-precision-BCE-century": "$1. Jahrhundert v. u. Z.", "wikibase-time-precision-BCE-10annum": "$1 Jahrzehnte v. u. Z.", diff --git a/extensions/Wikibase/lib/i18n/en.json b/extensions/Wikibase/lib/i18n/en.json index 1eeff22..391b71b 100644 --- a/extensions/Wikibase/lib/i18n/en.json +++ b/extensions/Wikibase/lib/i18n/en.json @@ -75,13 +75,13 @@ "version-wikibase": "Wikibase", "wikibase-time-precision-Gannum": "$1 billion years CE", "wikibase-time-precision-Mannum": "$1 million years CE", - "wikibase-time-precision-annum": "$1 years CE", + "wikibase-time-precision-annum": "{{PLURAL:$1|$1 year|$1 years}} CE", "wikibase-time-precision-millennium": "$1. millennium", "wikibase-time-precision-century": "$1. century", "wikibase-time-precision-10annum": "$1s", "wikibase-time-precision-BCE-Gannum": "$1 billion years BCE", "wikibase-time-precision-BCE-Mannum": "$1 million years BCE", - "wikibase-time-precision-BCE-annum": "$1 years BCE", + "wikibase-time-precision-BCE-annum": "{{PLURAL:$1|$1 year|$1 years}} BCE", "wikibase-time-precision-BCE-millennium": "$1. millennium BCE", "wikibase-time-precision-BCE-century": "$1. century BCE", "wikibase-time-precision-BCE-10annum": "$1s BCE", diff --git a/extensions/Wikibase/lib/i18n/zh-hant.json b/extensions/Wikibase/lib/i18n/zh-hant.json index 7e85002..3bdb05f 100644 --- a/extensions/Wikibase/lib/i18n/zh-hant.json +++ b/extensions/Wikibase/lib/i18n/zh-hant.json @@ -55,7 +55,7 @@ "wikibase-sitelinks-link-columnheading": "已連結的頁面", "wikibase-snakview-snaktypeselector-somevalue": "未知數值", "wikibase-snakview-snaktypeselector-novalue": "無數值", - "wikibase-tooltip-error-details": "詳細資訊", + "wikibase-tooltip-error-details": "詳細資料", "wikibase-undeserializable-value": "此數值無效,無法顯示。", "wikibase-validator-invalid": "無效的數值", "wikibase-validator-missing-field": "缺少必填欄位 \"$1\"", diff --git a/extensions/Wikibase/lib/tests/phpunit/EntityRevisionLookupTest.php b/extensions/Wikibase/lib/tests/phpunit/EntityRevisionLookupTest.php index 72f4e9b..11a23c0 100644 --- a/extensions/Wikibase/lib/tests/phpunit/EntityRevisionLookupTest.php +++ b/extensions/Wikibase/lib/tests/phpunit/EntityRevisionLookupTest.php @@ -2,7 +2,6 @@ namespace Wikibase\Test; -use ContentHandler; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\EntityRedirect; use Wikibase\DataModel\Entity\Item; diff --git a/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeTest.php b/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeTest.php index ff7b27e..142adc7 100644 --- a/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeTest.php +++ b/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeTest.php @@ -159,13 +159,13 @@ * @since 0.4 */ public function testToString( EntityChange $entityChange ) { - $s = "$entityChange"; // magically calls __toString() + $string = $entityChange->__toString(); - $id = $entityChange->getEntityId()->getSerialization(); + $id = strtolower( $entityChange->getEntityId()->getSerialization() ); $type = $entityChange->getType(); - $this->assertTrue( stripos( $s, $id ) !== false, "missing entity ID $id" ); - $this->assertTrue( stripos( $s, $type ) !== false, "missing type $type" ); + $this->assertContains( "'object_id' => '$id'", $string, "missing entity ID $id" ); + $this->assertContains( "'type' => '$type'", $string, "missing type $type" ); } public function testGetComment() { diff --git a/extensions/Wikibase/repo/Wikibase.hooks.php b/extensions/Wikibase/repo/Wikibase.hooks.php index eeb930d..0b4693c 100644 --- a/extensions/Wikibase/repo/Wikibase.hooks.php +++ b/extensions/Wikibase/repo/Wikibase.hooks.php @@ -350,18 +350,13 @@ 'type' => 'api' ); - if ( class_exists( 'Babel' ) ) { - $preferences['wikibase-entitytermsview-showEntitytermslistview'] = array( - 'type' => 'toggle', - 'label-message' => 'wikibase-setting-entitytermsview-showEntitytermslistview', - 'help-message' => 'wikibase-setting-entitytermsview-showEntitytermslistview-help', - 'section' => 'rendering/advancedrendering', - ); - } elseif ( $user->getBoolOption( 'wikibase-entitytermsview-showEntitytermslistview' ) ) { - // Clear setting after uninstalling Babel extension. - unset( $user->mOptions['wikibase-entitytermsview-showEntitytermslistview'] ); - $user->saveSettings(); - } + $preferences['wikibase-entitytermsview-showEntitytermslistview'] = array( + 'type' => 'toggle', + 'label-message' => 'wikibase-setting-entitytermsview-showEntitytermslistview', + 'help-message' => 'wikibase-setting-entitytermsview-showEntitytermslistview-help', + 'section' => 'rendering/advancedrendering', + 'default' => '1', + ); return true; } diff --git a/extensions/Wikibase/repo/i18n/el.json b/extensions/Wikibase/repo/i18n/el.json index 9d42ccb..8af3f34 100644 --- a/extensions/Wikibase/repo/i18n/el.json +++ b/extensions/Wikibase/repo/i18n/el.json @@ -8,7 +8,8 @@ "Indoril", "Evropi", "Macofe", - "Glavkos" + "Glavkos", + "Badseed" ] }, "wikibase-desc": "Αποθετήριο δομημένων δεδομένων", @@ -153,11 +154,11 @@ "wikibase-setdescription-introfull": "Ορίζετε την περιγραφή στα $2 για το [[$1]].", "wikibase-setdescription-label": "Περιγραφή:", "wikibase-setdescription-submit": "Προσθέστε μια περιγραφή", - "wikibase-setaliases-introfull": "Ορίζετε τα αλλώνυμα στα $2 για το [[$1]]. Πολλαπλά αλλώνυμα είναι διαχωρισμένα με τον χαρακτήρα πίπας (<code>|</code>).", + "wikibase-setaliases-introfull": "Ορίζετε τα αλλώνυμα στα $2 για το [[$1]]. Πολλαπλά αλλώνυμα διαχωρίζονται με τον χαρακτήρα καθέτου (<code>|</code>).", "wikibase-setaliases-label": "Αλλώνυμα:", "wikibase-setaliases-submit": "Ορίστε αλλώνυμα", "special-setlabeldescriptionaliases": "Ορίστε ετικέτα, περιγραφή και αλλώνυμα", - "wikibase-setlabeldescriptionaliases-introfull": "Ορίζετε ετικέτα, περιγραφή και αλλώνυμα στα $2 για το [[$1]]. Πολλαπλά αλλώνυμα είναι διαχωρισμένα με τον χαρακτήρα πίπας (<code>|</code>).", + "wikibase-setlabeldescriptionaliases-introfull": "Ορίζετε ετικέτα, περιγραφή και αλλώνυμα στα $2 για το [[$1]]. Πολλαπλά αλλώνυμα διαχωρίζονται με τον χαρακτήρα καθέτου (<code>|</code>).", "wikibase-setlabeldescriptionaliases-label-label": "Ετικέτα:", "wikibase-setlabeldescriptionaliases-description-label": "Περιγραφή:", "wikibase-setlabeldescriptionaliases-aliases-label": "Αλλώνυμα:", diff --git a/extensions/Wikibase/repo/i18n/gd.json b/extensions/Wikibase/repo/i18n/gd.json index 525f5a0..440d3d7 100644 --- a/extensions/Wikibase/repo/i18n/gd.json +++ b/extensions/Wikibase/repo/i18n/gd.json @@ -8,5 +8,10 @@ }, "wikibase-edit": "deasaich", "wikibase-add": "cuir ris", - "wikibase-sitelinks-special": "Làraichean eile" + "wikibase-label-empty": "Cha deach leubail a shònrachadh", + "wikibase-description-empty": "Cha deach tuairisgeul a shònrachadh", + "wikibase-sitelinks-special": "Làraichean eile", + "wikibase-aliases-empty": "Cha deach alias a shònrachadh", + "wikibase-statementview-rank-normal": "Inbhe àbhaisteach", + "wikibase-statementview-referencesheading-pendingcountersubject": "{{PLURAL:$1|tùs|thùs|tùsan|tùs}}" } diff --git a/extensions/Wikibase/repo/i18n/zh-hans.json b/extensions/Wikibase/repo/i18n/zh-hans.json index d42fd01..6ee8392 100644 --- a/extensions/Wikibase/repo/i18n/zh-hans.json +++ b/extensions/Wikibase/repo/i18n/zh-hans.json @@ -525,6 +525,7 @@ "apihelp-wbsetlabel-example-1": "为ID为“Q42”的页面设置字符串“Wikimedia”作为英语标签,并报告它为漂亮打印的json", "apihelp-wbsetlabel-example-2": "为带有英语维基 => \"Earth\"的项设置英语标签为“Earth”。", "apihelp-wbsetqualifier-description": "创建一个限定符或设置现有限定符的值。", + "apihelp-wbsetqualifier-param-value": "限定符的新值。\n只应为PropertyValueSnak限定符提供", "apihelp-wbsetqualifier-param-snakhash": "要修改的snak哈希。\n应只为存在的标识符提供", "apihelp-wbsetqualifier-param-summary": "编辑摘要。\n将按照自动生成的评论。自动评论与摘要的长度限制是260个字符。需要小心任何超出上述限定的东西将被裁剪掉。", "apihelp-wbsetqualifier-param-bot": "将此编辑标记为机器人编辑。此URL标记将只在用户属于“bot”用户组时受尊重。", diff --git a/extensions/Wikibase/repo/includes/EditEntity.php b/extensions/Wikibase/repo/includes/EditEntity.php index a061c92..bbd8394 100644 --- a/extensions/Wikibase/repo/includes/EditEntity.php +++ b/extensions/Wikibase/repo/includes/EditEntity.php @@ -2,8 +2,8 @@ namespace Wikibase; -use DerivativeContext; use Html; +use IContextSource; use InvalidArgumentException; use MWException; use ReadOnlyError; @@ -93,7 +93,7 @@ private $title = null; /** - * @var RequestContext|DerivativeContext + * @var IContextSource */ private $context; @@ -170,7 +170,7 @@ * This will detect "late" edit conflicts, i.e. someone squeezing in an edit * just before the actual database transaction for saving beings. * The empty string and 0 are both treated as `false`, disabling conflict checks. - * @param RequestContext|DerivativeContext|null $context the context to use while processing + * @param IContextSource|null $context the context to use while processing * the edit; defaults to RequestContext::getMain(). * * @throws InvalidArgumentException @@ -184,7 +184,7 @@ User $user, EditFilterHookRunner $editFilterHookRunner, $baseRevId = false, - $context = null + IContextSource $context = null ) { $this->newEntity = $newEntity; @@ -201,14 +201,6 @@ $this->errorType = 0; $this->status = Status::newGood(); - - if ( $context !== null - && !( $context instanceof RequestContext ) - && !( $context instanceof DerivativeContext ) - ) { - throw new InvalidArgumentException( '$context must be an instance of RequestContext' - . ' or DerivativeContext' ); - } if ( $context === null ) { $context = RequestContext::getMain(); diff --git a/extensions/Wikibase/repo/includes/EditEntityFactory.php b/extensions/Wikibase/repo/includes/EditEntityFactory.php index cd58259..cc4bc59 100644 --- a/extensions/Wikibase/repo/includes/EditEntityFactory.php +++ b/extensions/Wikibase/repo/includes/EditEntityFactory.php @@ -2,8 +2,7 @@ namespace Wikibase; -use DerivativeContext; -use RequestContext; +use IContextSource; use User; use Wikibase\DataModel\Entity\Entity; use Wikibase\Lib\Store\EntityRevisionLookup; @@ -46,7 +45,7 @@ private $editFilterHookRunner; /** - * @var RequestContext|DerivativeContext|null + * @var IContextSource|null */ private $context; @@ -56,7 +55,7 @@ * @param EntityStore $entityStore * @param EntityPermissionChecker $permissionChecker * @param EditFilterHookRunner $editFilterHookRunner - * @param RequestContext|DerivativeContext|null $context + * @param IContextSource|null $context */ public function __construct( EntityTitleLookup $titleLookup, @@ -64,7 +63,7 @@ EntityStore $entityStore, EntityPermissionChecker $permissionChecker, EditFilterHookRunner $editFilterHookRunner, - $context = null + IContextSource $context = null ) { $this->titleLookup = $titleLookup; $this->entityRevisionLookup = $entityLookup; diff --git a/extensions/Wikibase/repo/includes/Hooks/EditFilterHookRunner.php b/extensions/Wikibase/repo/includes/Hooks/EditFilterHookRunner.php index 1de1a6d..8e199e5 100644 --- a/extensions/Wikibase/repo/includes/Hooks/EditFilterHookRunner.php +++ b/extensions/Wikibase/repo/includes/Hooks/EditFilterHookRunner.php @@ -38,7 +38,7 @@ private $entityContentFactory; /** - * @var IContextSource + * @var MutableContext */ private $context; @@ -52,6 +52,12 @@ EntityContentFactory $entityContentFactory, IContextSource $context ) { + if ( !( $context instanceof MutableContext ) ) { + wfLogWarning( '$context is not an instanceof MutableContext.' ); + + $context = new DerivativeContext( $context ); + } + $this->titleLookup = $titleLookup; $this->entityContentFactory = $entityContentFactory; $this->context = $context; @@ -131,12 +137,6 @@ // namespace IDs for Property entities. $namespace = $this->titleLookup->getNamespaceForType( $entityType ); $title = Title::makeTitle( $namespace, 'New' . ucfirst( $entityType ) ); - } - - if ( !( $context instanceof MutableContext ) ) { - wfLogWarning( '$context is not an instanceof MutableContext.' ); - - $context = new DerivativeContext( $context ); } $context->setTitle( $title ); diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/ParserOutput/PageImagesDataUpdaterTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/ParserOutput/PageImagesDataUpdaterTest.php index 3849361..fcadef5 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/ParserOutput/PageImagesDataUpdaterTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/ParserOutput/PageImagesDataUpdaterTest.php @@ -131,6 +131,8 @@ 'Property not found' => array( $statements, array( 'P9999' ), null ), 'Not a property id' => array( $statements, array( 'Q1' ), null ), 'Invalid id' => array( $statements, array( 'invalid' ), null ), + + // Configuration 'Ignore misconfiguration' => array( $statements, array( 'P1', 'P2', 'P1' ), '1.jpg' ), 'Ignore keys' => array( $statements, array( 2 => 'P1', 1 => 'P2' ), '1.jpg' ), @@ -144,8 +146,10 @@ 'Increasing order' => array( $statements, array( 'P1', 'P2', 'P3' ), '1.jpg' ), 'Decreasing order' => array( $statements, array( 'P3', 'P2', 'P1' ), '3a.jpg' ), + // Ranks 'Skip deprecated' => array( $statements, array( 'P4' ), 'Four_2.jpg' ), 'Prefer preferred' => array( $statements, array( 'P5' ), '5c.jpg' ), + 'Rank does not overrule priority' => array( $statements, array( 'P1', 'P5' ), '1.jpg' ), ); } diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/store/sql/EntityPerPageBuilderTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/store/sql/EntityPerPageBuilderTest.php index 15ca610..5eba0fa 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/store/sql/EntityPerPageBuilderTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/store/sql/EntityPerPageBuilderTest.php @@ -2,7 +2,6 @@ namespace Wikibase\Test; -use ContentHandler; use RuntimeException; use User; use Wikibase\DataModel\Entity\EntityRedirect; diff --git a/extensions/Wikibase/view/src/EntityTermsView.php b/extensions/Wikibase/view/src/EntityTermsView.php index 65aa246..05b3648 100644 --- a/extensions/Wikibase/view/src/EntityTermsView.php +++ b/extensions/Wikibase/view/src/EntityTermsView.php @@ -188,10 +188,10 @@ } return $this->templateFactory->render( 'wikibase-entitytermsforlanguagelistview', - $this->msg( 'wikibase-entitytermsforlanguagelistview-language' ), - $this->msg( 'wikibase-entitytermsforlanguagelistview-label' ), - $this->msg( 'wikibase-entitytermsforlanguagelistview-description' ), - $this->msg( 'wikibase-entitytermsforlanguagelistview-aliases' ), + $this->msg( 'wikibase-entitytermsforlanguagelistview-language' )->escaped(), + $this->msg( 'wikibase-entitytermsforlanguagelistview-label' )->escaped(), + $this->msg( 'wikibase-entitytermsforlanguagelistview-description' )->escaped(), + $this->msg( 'wikibase-entitytermsforlanguagelistview-aliases' )->escaped(), $entityTermsForLanguageViewsHtml ); } diff --git a/extensions/Wikibase/view/src/EntityViewPlaceholderExpander.php b/extensions/Wikibase/view/src/EntityViewPlaceholderExpander.php index 1c49f1c..dc679ef 100644 --- a/extensions/Wikibase/view/src/EntityViewPlaceholderExpander.php +++ b/extensions/Wikibase/view/src/EntityViewPlaceholderExpander.php @@ -211,16 +211,7 @@ isset( $args[1] ) ? (int)$args[1] : 0 ); case 'entityViewPlaceholder-entitytermsview-entitytermsforlanguagelistview-class': - return - !$this->user->isAnon() - && $this->user->getBoolOption( - 'wikibase-entitytermsview-showEntitytermslistview' - ) - || $this->user->isAnon() - && isset( $_COOKIE['wikibase-entitytermsview-showEntitytermslistview'] ) - && $_COOKIE['wikibase-entitytermsview-showEntitytermslistview'] === 'true' - ? '' : 'wikibase-initially-collapsed'; - + return $this->isInitiallyCollapsed() ? 'wikibase-initially-collapsed' : ''; default: wfWarn( "Unknown placeholder: $name" ); return '(((' . htmlspecialchars( $name ) . ')))'; @@ -228,6 +219,18 @@ } /** + * @return bool If the terms list should be initially collapsed for the current user. + */ + private function isInitiallyCollapsed() { + if ( $this->user->isAnon() ) { + return isset( $_COOKIE['wikibase-entitytermsview-showEntitytermslistview'] ) + && $_COOKIE['wikibase-entitytermsview-showEntitytermslistview'] === 'false'; + } else { + return !$this->user->getBoolOption( 'wikibase-entitytermsview-showEntitytermslistview' ); + } + } + + /** * Generates HTML of the term box, to be injected into the entity page. * * @param EntityId $entityId diff --git a/extensions/Wikibase/view/tests/phpunit/EntityTermsViewTest.php b/extensions/Wikibase/view/tests/phpunit/EntityTermsViewTest.php index 60537d8..6dbd9da 100644 --- a/extensions/Wikibase/view/tests/phpunit/EntityTermsViewTest.php +++ b/extensions/Wikibase/view/tests/phpunit/EntityTermsViewTest.php @@ -4,6 +4,7 @@ use Language; use MediaWikiLangTestCase; +use MessageCache; use Wikibase\DataModel\Entity\ItemId; use Wikibase\DataModel\Term\Fingerprint; use Wikibase\View\EntityTermsView; @@ -240,9 +241,21 @@ $this->assertNotContains( '&', $html, 'no double escaping' ); } + public function testGetEntityTermsForLanguageListView_isEscaped() { + MessageCache::singleton()->enable(); + $this->setMwGlobals( 'wgLang', Language::factory( 'en' ) ); + $this->insertPage( 'MediaWiki:wikibase-entitytermsforlanguagelistview-language', "''RAW''" ); + + $view = $this->getEntityTermsView(); + $html = $view->getEntityTermsForLanguageListView( new Fingerprint(), array() ); + + $this->assertContains( '''RAW''', $html ); + $this->assertNotContains( "'RAW'", $html ); + } + public function testGetEntityTermsForLanguageListView_isMarkedAsEmpty() { $view = $this->getEntityTermsView( 0, 1 ); - $html = $view->getEntityTermsForLanguageListView( new Fingerprint(), array( 'en' ), null ); + $html = $view->getEntityTermsForLanguageListView( new Fingerprint(), array( 'en' ) ); $this->assertContains( 'wb-empty', $html ); $this->assertContains( '(wikibase-label-empty)', $html ); diff --git a/extensions/WikimediaBadges/WikimediaBadges.php b/extensions/WikimediaBadges/WikimediaBadges.php index 77402aa..1767743 100644 --- a/extensions/WikimediaBadges/WikimediaBadges.php +++ b/extensions/WikimediaBadges/WikimediaBadges.php @@ -31,6 +31,16 @@ $GLOBALS['wgMessagesDirs']['WikimediaBadges'] = __DIR__ . '/i18n'; +/** + * The Property id of the commons category property. + * This is used to construct the link target for the other projects + * sidebar link to Wikimedia Commons. + * + * Set this to null in order to disable the other projects + * sidebar replacement. + */ +$GLOBALS['wgWikimediaBadgesCommonsCategoryProperty'] = 'P373'; + $GLOBALS['wgExtensionFunctions'][] = function() { global $wgExtensionCredits, $wgHooks, $wgResourceModules; @@ -38,14 +48,20 @@ 'path' => __FILE__, 'name' => 'WikimediaBadges', 'version' => WIKIMEDIA_BADGES_VERSION, - 'author' => '[https://www.mediawiki.org/wiki/User:Bene* Bene*]', + 'author' => array( '[https://www.mediawiki.org/wiki/User:Bene* Bene*]', 'Marius Hoch' ), 'url' => 'https://github.com/wmde/WikimediaBadges', 'descriptionmsg' => 'wikimedia-badges-desc', 'license-name' => 'GPL-2.0+' ); // Hooks - $wgHooks['BeforePageDisplay'][] = 'WikimediaBadges\Hooks::onBeforePageDisplay'; + $wgHooks['BeforePageDisplay'][] = 'WikimediaBadges\BeforePageDisplayHookHandler::onBeforePageDisplay'; + $wgHooks['WikibaseClientOtherProjectsSidebar'][] = 'WikimediaBadges\OtherProjectsSidebarHookHandler::addToSidebar'; + + // Register phpunit tests + $wgHooks['UnitTestsList'][] = function( array &$files ) { + $files[] = __DIR__ . '/tests/phpunit'; + }; // Resource Loader modules $wgResourceModules = array_merge( $wgResourceModules, include __DIR__ . '/resources/Resources.php' ); diff --git a/extensions/WikimediaBadges/composer.json b/extensions/WikimediaBadges/composer.json index bec0688..45eb3b3 100644 --- a/extensions/WikimediaBadges/composer.json +++ b/extensions/WikimediaBadges/composer.json @@ -27,8 +27,8 @@ "files": [ "WikimediaBadges.php" ], - "classmap": [ - "WikimediaBadges.hooks.php" - ] + "psr-4": { + "WikimediaBadges\\": "includes/" + } } } diff --git a/extensions/WikimediaBadges/WikimediaBadges.hooks.php b/extensions/WikimediaBadges/includes/BeforePageDisplayHookHandler.php similarity index 83% rename from extensions/WikimediaBadges/WikimediaBadges.hooks.php rename to extensions/WikimediaBadges/includes/BeforePageDisplayHookHandler.php index 33a1845..adda0f1 100644 --- a/extensions/WikimediaBadges/WikimediaBadges.hooks.php +++ b/extensions/WikimediaBadges/includes/BeforePageDisplayHookHandler.php @@ -6,14 +6,14 @@ use Skin; /** - * File defining the hook handlers for the WikimediaBadges extension. + * Handler for the BeforePageDisplay hook. * * @since 0.1 * * @license GNU GPL v2+ * @author Bene* < benestar.wikime...@gmail.com > */ -final class Hooks { +class BeforePageDisplayHookHandler { /** * Handler for the BeforePageDisplay hook diff --git a/extensions/WikimediaBadges/includes/OtherProjectsSidebarHookHandler.php b/extensions/WikimediaBadges/includes/OtherProjectsSidebarHookHandler.php new file mode 100644 index 0000000..3156f4e --- /dev/null +++ b/extensions/WikimediaBadges/includes/OtherProjectsSidebarHookHandler.php @@ -0,0 +1,213 @@ +<?php + +namespace WikimediaBadges; + +use DataValues\StringValue; +use RequestContext; +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\DataModel\Entity\PropertyId; +use Wikibase\DataModel\Services\Lookup\EntityLookup; +use Wikibase\DataModel\Services\Lookup\EntityLookupException; +use Wikibase\DataModel\Snak\PropertyValueSnak; +use Wikibase\Client\WikibaseClient; +use Wikimedia\Assert\Assert; +use Wikimedia\Assert\ParameterTypeException; + +/** + * Handler for the WikibaseClientOtherProjectsSidebar hook that changes the link + * to Wikimedia Commons with the one to the commons category. + * + * @since 0.1 + * + * @license GNU GPL v2+ + * @author Marius Hoch < h...@online.de > + */ +class OtherProjectsSidebarHookHandler { + + /** + * @var EntityLookup + */ + private $entityLookup; + + /** + * @var string|null + */ + private $commonsCategoryPropertySetting; + + /** + * @return self + */ + private static function newFromGlobalState() { + $wikibaseClient = WikibaseClient::getDefaultInstance(); + + return new self( + $wikibaseClient->getStore()->getEntityLookup(), + RequestContext::getMain()->getConfig()->get( 'WikimediaBadgesCommonsCategoryProperty' ) + ); + } + + /** + * @param EntityLookup $entityLookup + * @param string|null $commonsCategoryPropertySetting + * + * @throws ParameterTypeException + */ + public function __construct( EntityLookup $entityLookup, $commonsCategoryPropertySetting ) { + Assert::parameterType( 'string|null', $commonsCategoryPropertySetting, '$commonsCategoryPropertySetting' ); + + $this->entityLookup = $entityLookup; + $this->commonsCategoryPropertySetting = $commonsCategoryPropertySetting; + } + + /** + * @since 0.1 + * + * @param ItemId $itemId + * @param array &$sidebar + * + * @return bool + */ + public static function addToSidebar( ItemId $itemId, array &$sidebar ) { + $self = self::newFromGlobalState(); + + return $self->doAddToSidebar( $itemId, $sidebar ); + } + + /** + * @since 0.1 + * + * @param ItemId $itemId + * @param array &$sidebar + * + * @return bool + */ + public function doAddToSidebar( ItemId $itemId, array &$sidebar ) { + if ( $this->commonsCategoryPropertySetting !== null + ) { + $categoryName = $this->getCommonsCategoryName( $itemId ); + if ( $categoryName !== null ) { + $this->handleCategoryName( $categoryName, $sidebar ); + } + } + + return true; + } + + /** + * @param string $categoryName + * @param array &$sidebar + */ + private function handleCategoryName( $categoryName, array &$sidebar ) { + $href = 'https://commons.wikimedia.org/wiki/Category:' . + wfUrlencode( str_replace( ' ', '_', $categoryName ) ); + + $this->modifyOrAddEntry( $href, $sidebar ); + } + + /** + * @param string $href Link to the commons category + * @param array &$sidebar + */ + private function modifyOrAddEntry( $href, array &$sidebar ) { + if ( isset( $sidebar['commons']['commonswiki'] ) ) { + $sidebar['commons']['commonswiki']['href'] = $href; + + return; + } + + $sidebar['commons'] = array( + 'commonswiki' => array( + 'msg' => 'wikibase-otherprojects-commons', + 'class' => 'wb-otherproject-link wb-otherproject-commons', + 'href' => $href, + 'hreflang' => 'en' + ) + ); + } + + /** + * @param ItemId $itemId + * + * @return string|null + */ + private function getCommonsCategoryName( ItemId $itemId ) { + $item = $this->getItem( $itemId ); + + if ( !$item ) { + return null; + } + + return $this->getCommonsCategoryNameFromItem( $item ); + } + + /** + * @param Item $item + * + * @return string|null + */ + private function getCommonsCategoryNameFromItem( Item $item ) { + $propertyId = new PropertyId( $this->commonsCategoryPropertySetting ); + $statements = $item->getStatements()->getByPropertyId( $propertyId ); + + $mainSnaks = $statements->getBestStatements()->getMainSnaks(); + + return $this->getCommonsCategoryNameFromMainSnaks( + $mainSnaks, + $item->getId(), + $propertyId + ); + } + + /** + * @param Snak[] $mainSnaks + * @param ItemId $itemId + * @param PropertyId $propertyId + * + * @return string|null + */ + private function getCommonsCategoryNameFromMainSnaks( + array $mainSnaks, + ItemId $itemId, + PropertyId $propertyId + ) { + foreach ( $mainSnaks as $snak ) { + if ( !( $snak instanceof PropertyValueSnak ) ) { + continue; + } + + if ( !( $snak->getDataValue() instanceof StringValue ) ) { + wfLogWarning( + $itemId->getSerialization() . ' has a PropertyValueSnak with ' . + $propertyId->getSerialization() . ' that has non-StringValue data.' + ); + + continue; + } + + return $snak->getDataValue()->getValue(); + } + + return null; + } + + /** + * @param ItemId $itemId + * + * @return Item|null + */ + private function getItem( ItemId $itemId ) { + try { + $item = $this->entityLookup->getEntity( $itemId ); + } catch( EntityLookupException $ex ) { + wfLogWarning( + "Failed to load Item $itemId: " . $ex->getMessage() + ); + + return null; + } + + return $item; + } + +} diff --git a/extensions/WikimediaBadges/tests/phpunit/includes/BeforePageDisplayHookHandlerTest.php b/extensions/WikimediaBadges/tests/phpunit/includes/BeforePageDisplayHookHandlerTest.php new file mode 100644 index 0000000..9a409b7 --- /dev/null +++ b/extensions/WikimediaBadges/tests/phpunit/includes/BeforePageDisplayHookHandlerTest.php @@ -0,0 +1,31 @@ +<?php + +namespace WikimediaBadges\Tests; + +use PHPUnit_Framework_TestCase; +use SkinTemplate; +use WikimediaBadges\BeforePageDisplayHookHandler; + +/** + * @covers WikimediaBadges\BeforePageDisplayHookHandler + * + * @group WikimediaBadges + * + * @license GNU GPL v2+ + * @author Marius Hoch < h...@online.de > + */ +class BeforePageDisplayHookHandlerTest extends PHPUnit_Framework_TestCase { + + public function testOnBeforePageDisplay() { + $skin = new SkinTemplate(); + $out = $this->getMockBuilder( 'OutputPage' ) + ->disableOriginalConstructor() + ->getMock(); + $out->expects( $this->once() ) + ->method( 'addModuleStyles' ) + ->with( 'ext.wikimediaBadges' ); + + $this->assertTrue( BeforePageDisplayHookHandler::onBeforePageDisplay( $out, $skin ) ); + } + +} diff --git a/extensions/WikimediaBadges/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php b/extensions/WikimediaBadges/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php new file mode 100644 index 0000000..3ed8a93 --- /dev/null +++ b/extensions/WikimediaBadges/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php @@ -0,0 +1,210 @@ +<?php + +namespace WikimediaBadges\Tests; + +use DataValues\StringValue; +use DataValues\DecimalValue; +use MediaWikiTestCase; +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\DataModel\Entity\PropertyId; +use Wikibase\DataModel\Snak\PropertySomeValueSnak; +use Wikibase\DataModel\Snak\PropertyValueSnak; +use Wikibase\DataModel\Services\Lookup\InMemoryEntityLookup; +use Wikibase\DataModel\Services\Lookup\EntityLookupException; +use WikimediaBadges\OtherProjectsSidebarHookHandler; + +/** + * @covers WikimediaBadges\OtherProjectsSidebarHookHandler + * + * @group WikimediaBadges + * + * @license GNU GPL v2+ + * @author Marius Hoch < h...@online.de > + */ +class OtherProjectsSidebarHookHandlerTest extends MediaWikiTestCase { + + /** + * @dataProvider doAddToSidebarProvider + */ + public function testDoAddToSidebar( array $expected, array $sidebar, ItemId $itemId, $suppressErrors = false ) { + $handler = new OtherProjectsSidebarHookHandler( + $this->getEntityLookup(), + 'P373' + ); + + if ( $suppressErrors === 'suppress' ) { + \MediaWiki\suppressWarnings(); + } + $this->assertTrue( $handler->doAddToSidebar( $itemId, $sidebar ) ); + if ( $suppressErrors === 'suppress' ) { + \MediaWiki\restoreWarnings(); + } + + $this->assertSame( $expected, $sidebar ); + } + + public function doAddToSidebarProvider() { + $wikiquoteLink = array( + 'msg' => 'wikibase-otherprojects-wikiquote', + 'class' => 'wb-otherproject-link wb-otherproject-wikiquote', + 'href' => 'https://en.wikiquote.org/wiki/Ams', + 'hreflang' => 'en' + ); + $oldCommonsLink = array( + 'msg' => 'wikibase-otherprojects-commons', + 'class' => 'wb-otherproject-link wb-otherproject-commons', + 'href' => 'https://commons.wikimedia.org/wiki/Amsterdam', + 'hreflang' => 'en' + ); + $newCommonsLink = $oldCommonsLink; + $newCommonsLink['href'] = 'https://commons.wikimedia.org/wiki/Category:Amsterdam'; + + return array( + 'Item without commons category statement' => array( + array(), + array(), + new ItemId( 'Q2013' ) + ), + 'Sidebar without commons link gets amended' => array( + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $newCommonsLink ) + ), + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ) + ), + new ItemId( 'Q123' ) + ), + 'Empty sidebar gets amended' => array( + array( 'commons' => array( 'commonswiki' => $newCommonsLink ) ), + array(), + new ItemId( 'Q123' ) + ), + 'Existing commons link gets amended' => array( + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $newCommonsLink ) + ), + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $oldCommonsLink ) + ), + new ItemId( 'Q123' ) + ), + 'No such item' => array( + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $oldCommonsLink ) + ), + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $oldCommonsLink ) + ), + new ItemId( 'Q404' ) + ), + 'Item loading failed' => array( + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $oldCommonsLink ) + ), + array( + 'wikiquote' => array( 'enwikiquote' => $wikiquoteLink ), + 'commons' => array( 'commonswiki' => $oldCommonsLink ) + ), + new ItemId( 'Q503' ), + 'suppress' + ), + ); + } + + public function testDoAddToSidebar_disabled() { + $entityLookup = $this->getMock( 'Wikibase\DataModel\Services\Lookup\EntityLookup' ); + $entityLookup->expects( $this->never() ) + ->method( 'getEntity' ); + + $handler = new OtherProjectsSidebarHookHandler( + $entityLookup, + null + ); + + $sidebar = array( 101010 => array( 'blah' ) ); + $origSidebar = $sidebar; + $this->assertTrue( $handler->doAddToSidebar( new ItemId( 'Q42' ), $sidebar ) ); + $this->assertSame( $origSidebar, $sidebar ); + } + + /** + * @dataProvider constructor_invalidSettingProvider + */ + public function testConstructor_invalidSetting( $value ) { + $this->setExpectedException( 'Wikimedia\Assert\ParameterTypeException' ); + + new OtherProjectsSidebarHookHandler( + $this->getMock( 'Wikibase\DataModel\Services\Lookup\EntityLookup' ), + $value + ); + } + + public function constructor_invalidSettingProvider() { + return array( + array( array( ':(' ) ), + array( function() {} ), + array( false ) + ); + } + + public function testDoAddToSidebar_invalidDataValue() { + $entityLookup = new InMemoryEntityLookup(); + $propertyId = new PropertyId( 'P12' ); + $mainSnak = new PropertyValueSnak( $propertyId, new DecimalValue( 1 ) ); + + $item = new Item( new ItemId( 'Q123' ) ); + $item->getStatements()->addNewStatement( $mainSnak ); + $entityLookup->addEntity( $item ); + + $handler = new OtherProjectsSidebarHookHandler( + $entityLookup, + 'P12' + ); + + $sidebar = array( 101010 => array( 'blah' ) ); + $origSidebar = $sidebar; + + \MediaWiki\suppressWarnings(); + $this->assertTrue( $handler->doAddToSidebar( new ItemId( 'Q123' ), $sidebar ) ); + \MediaWiki\restoreWarnings(); + + $this->assertSame( $origSidebar, $sidebar ); + } + + public function testAddToSidebar() { + // Integration test: Make sure this doesn't fatal + $this->setMwGlobals( 'wgWikimediaBadgesCommonsCategoryProperty', null ); + $sidebar = array(); + + $this->assertTrue( + OtherProjectsSidebarHookHandler::addToSidebar( new ItemId( 'Q38434234' ), $sidebar ) + ); + } + + private function getEntityLookup() { + $entityLookup = new InMemoryEntityLookup(); + $propertyId = new PropertyId( 'P373' ); + + $mainSnak = new PropertyValueSnak( $propertyId, new StringValue( 'Amsterdam' ) ); + + $item = new Item( new ItemId( 'Q123' ) ); + $item->getStatements()->addNewStatement( $mainSnak ); + $item->getStatements()->addNewStatement( new PropertySomeValueSnak( $propertyId ) ); + + $exception = new EntityLookupException( new ItemId( 'Q503' ) ); + + $entityLookup->addEntity( $item ); + $entityLookup->addEntity( new Item( new ItemId( 'Q2013' ) ) ); + $entityLookup->addException( $exception ); + + return $entityLookup; + } + +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 9317b5b..ff6e27a 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -1497,7 +1497,8 @@ 'Wikidata\\SettingsFileGenerator' => $baseDir . '/src/SettingsFileGenerator.php', 'Wikidata\\WikidataHooks' => $baseDir . '/src/WikidataHooks.php', 'Wikidata\\WikidataSettingsBuilder' => $baseDir . '/src/WikidataSettingsBuilder.php', - 'WikimediaBadges\\Hooks' => $baseDir . '/extensions/WikimediaBadges/WikimediaBadges.hooks.php', + 'WikimediaBadges\\BeforePageDisplayHookHandler' => $baseDir . '/extensions/WikimediaBadges/includes/BeforePageDisplayHookHandler.php', + 'WikimediaBadges\\OtherProjectsSidebarHookHandler' => $baseDir . '/extensions/WikimediaBadges/includes/OtherProjectsSidebarHookHandler.php', 'Wikimedia\\Purtle\\BNodeLabeler' => $baseDir . '/extensions/Wikibase/purtle/src/BNodeLabeler.php', 'Wikimedia\\Purtle\\N3Quoter' => $baseDir . '/extensions/Wikibase/purtle/src/N3Quoter.php', 'Wikimedia\\Purtle\\N3RdfWriterBase' => $baseDir . '/extensions/Wikibase/purtle/src/N3RdfWriterBase.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 0fb010a..0c00fcb 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -8,6 +8,7 @@ return array( 'Wikimedia\\Purtle\\Tests\\' => array($baseDir . '/extensions/Wikibase/purtle/tests/phpunit'), 'Wikimedia\\Purtle\\' => array($baseDir . '/extensions/Wikibase/purtle/src'), + 'WikimediaBadges\\' => array($baseDir . '/extensions/WikimediaBadges/includes'), 'Wikidata\\' => array($baseDir . '/src'), 'Wikibase\\View\\Tests\\' => array($baseDir . '/extensions/Wikibase/view/tests/phpunit'), 'Wikibase\\View\\' => array($baseDir . '/extensions/Wikibase/view/src'), diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 574631b..4f71e47 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1237,12 +1237,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd" + "reference": "53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd", - "reference": "b4111f6820ab6e1f6072d2b1bf4b3fddd3f775bd", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9", + "reference": "53f56d3496a13a8ccb8c85ee4fb96001bac9b2c9", "shasum": "" }, "require": { @@ -1274,7 +1274,7 @@ "jakub-onderka/php-parallel-lint": "0.9.2", "mediawiki/mediawiki-codesniffer": "0.4.0|0.5.0" }, - "time": "2016-01-21 03:04:33", + "time": "2016-01-26 09:44:07", "type": "mediawiki-extension", "installation-source": "dist", "autoload": { @@ -1323,21 +1323,21 @@ "source": { "type": "git", "url": "https://gerrit.wikimedia.org/r/mediawiki/extensions/WikimediaBadges", - "reference": "22cfee80965d12162f97405d38ed8ec32f56e59c" + "reference": "885441b2e0f3cab5f8b5731cf22581309dee2735" }, "require": { "php": ">=5.3.0" }, - "time": "2016-01-18 13:08:32", + "time": "2016-01-21 13:15:32", "type": "mediawiki-extension", "installation-source": "source", "autoload": { "files": [ "WikimediaBadges.php" ], - "classmap": [ - "WikimediaBadges.hooks.php" - ] + "psr-4": { + "WikimediaBadges\\": "includes/" + } }, "license": [ "GNU GPL v2+" -- To view, visit https://gerrit.wikimedia.org/r/266478 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I2f1b16ff103dba876493aa72f16a2d33f3f80879 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikidata Gerrit-Branch: master Gerrit-Owner: WikidataBuilder <wikidata-servi...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits