jenkins-bot has submitted this change and it was merged.

Change subject: Override commons sidebar link with commons category
......................................................................


Override commons sidebar link with commons category

This does not implement any form of cache invalidation,
but that is ok for now.

The sidebar itself is cached within the ParserCache, so
this is only being executed on parse.

Bug: T94989
Change-Id: I96163f37bc86e78096e13a8db62adcd6d6c77fec
---
M WikimediaBadges.php
A includes/OtherProjectsSidebarHookHandler.php
A tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php
3 files changed, 435 insertions(+), 1 deletion(-)

Approvals:
  Aude: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/WikimediaBadges.php b/WikimediaBadges.php
index 38be701..96aeb1e 100644
--- a/WikimediaBadges.php
+++ b/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,7 +48,7 @@
                '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+'
@@ -46,6 +56,7 @@
 
        // Hooks
        $wgHooks['BeforePageDisplay'][] = 
'WikimediaBadges\BeforePageDisplayHookHandler::onBeforePageDisplay';
+       $wgHooks['WikibaseClientOtherProjectsSidebar'][] = 
'WikimediaBadges\OtherProjectsSidebarHookHandler::addToSidebar';
 
        // Register phpunit tests
        $wgHooks['UnitTestsList'][] = function( array &$files ) {
diff --git a/includes/OtherProjectsSidebarHookHandler.php 
b/includes/OtherProjectsSidebarHookHandler.php
new file mode 100644
index 0000000..3156f4e
--- /dev/null
+++ b/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 < [email protected] >
+ */
+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/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php 
b/tests/phpunit/includes/OtherProjectsSidebarHookHandlerTest.php
new file mode 100644
index 0000000..3ed8a93
--- /dev/null
+++ b/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 < [email protected] >
+ */
+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;
+       }
+
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/264597
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I96163f37bc86e78096e13a8db62adcd6d6c77fec
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/WikimediaBadges
Gerrit-Branch: master
Gerrit-Owner: Hoo man <[email protected]>
Gerrit-Reviewer: Addshore <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: Bene <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: JanZerebecki <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: Tpt <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to