Dominic.sauer has submitted this change and it was merged.

Change subject: Special pages now contain the lines they used to inherit
......................................................................


Special pages now contain the lines they used to inherit

Change-Id: I601c334f8faaa4651db6f21ba6f1ebaba4eeb27f
---
M WikidataQualityExternalValidation.php
A modules/SpecialExternalValidationPage.css
M specials/SpecialCrossCheck.php
M specials/SpecialExternalDbs.php
4 files changed, 589 insertions(+), 12 deletions(-)

Approvals:
  Dominic.sauer: Verified; Looks good to me, approved



diff --git a/WikidataQualityExternalValidation.php 
b/WikidataQualityExternalValidation.php
index e9caee9..12b5426 100644
--- a/WikidataQualityExternalValidation.php
+++ b/WikidataQualityExternalValidation.php
@@ -41,6 +41,13 @@
        // Define API modules
        $GLOBALS['wgAPIModules']['wdqacrosscheck'] = 
'WikidataQuality\ExternalValidation\Api\CrossCheck';
 
+       // Define modules
+       $GLOBALS['wgResourceModules']['SpecialExternalValidationPage'] = array (
+               'styles' => '/modules/SpecialExternalValidationPage.css',
+               'localBasePath' => __DIR__,
+               'remoteExtPath' => 'WikidataQualityExternalValidation'
+       );
+
        // Define database table names
        define( 'DUMP_DATA_TABLE', 'wdqa_external_data' );
        define( 'DUMP_META_TABLE', 'wdqa_dump_information' );
diff --git a/modules/SpecialExternalValidationPage.css 
b/modules/SpecialExternalValidationPage.css
new file mode 100644
index 0000000..d628c9c
--- /dev/null
+++ b/modules/SpecialExternalValidationPage.css
@@ -0,0 +1,83 @@
+/* Entity id form */
+.wbq-checkresult-form {
+    margin-top: 10px;
+    margin-bottom: 20px;
+}
+
+.wbq-checkresult-form-entity-id {
+    width: 120px;
+}
+
+.wbq-checkresult-form-submit {
+    margin-left: 5px;
+}
+
+/* Notices */
+.wbq-checkresult-notice {
+    font-style: italic;
+}
+
+.wbq-checkresult-notice-error {
+    font-weight: bold;
+    color: #BA0000;
+}
+
+/* Statuses */
+.wbq-status {
+    font-weight: bold;
+}
+
+.wbq-status-success {
+    color: #008000;
+}
+
+.wbq-status-partial-success {
+    color: #6CB500;
+}
+
+.wbq-status-warning {
+    color: #E6B800;
+}
+
+.wbq-status-error {
+    color: #BA0000;
+}
+
+.wbq-status-unknown {
+    color: #404040;
+}
+
+/* Tooltip */
+.wbq-tooltip-indicator:before {
+    content: '[?]';
+    color: #CCC;
+    font-weight: 600;
+}
+
+[tooltip]:before {
+    /* needed - do not touch */
+    content: attr(tooltip);
+    position: absolute;
+    opacity: 0;
+
+    /* customizable */
+    transition: all 0.20s ease;
+    padding: 5px;
+    border: 1px solid #AAA;
+    border-radius: 5px;
+    box-shadow: 2px 2px 1px #CCC;
+}
+
+[tooltip]:hover:before {
+    /* needed - do not touch */
+    opacity: 1;
+
+    /* customizable */
+    background: #F2F2F2;
+    margin-top: -35px;
+    margin-left: -5px;
+}
+
+[tooltip]:not([tooltip-persistent]):before {
+    pointer-events: none;
+}
\ No newline at end of file
diff --git a/specials/SpecialCrossCheck.php b/specials/SpecialCrossCheck.php
index ccd4ec0..12f6bc5 100755
--- a/specials/SpecialCrossCheck.php
+++ b/specials/SpecialCrossCheck.php
@@ -2,13 +2,28 @@
 
 namespace WikidataQuality\ExternalValidation\Specials;
 
+use SpecialPage;
+use ValueFormatters\FormatterOptions;
+use Wikibase\Lib\EntityIdLabelFormatter;
+use Wikibase\Lib\EntityIdHtmlLinkFormatter;
+use Wikibase\Lib\EntityIdLinkFormatter;
+use Wikibase\Lib\HtmlUrlFormatter;
+use Wikibase\Lib\LanguageNameLookup;
+use Wikibase\Lib\SnakFormatter;
+use Wikibase\Lib\Store\LanguageLabelDescriptionLookup;
+use Wikibase\Repo\WikibaseRepo;
 use Html;
 use JobQueueGroup;
 use Linker;
 use Traversable;
 use Wikibase\DataModel\Entity\Entity;
 use Wikibase\DataModel\Entity\EntityId;
-use Wikibase\Repo\WikibaseRepo;
+use DataValues\DataValue;
+use Doctrine\Instantiator\Exception\InvalidArgumentException;
+use Doctrine\Instantiator\Exception\UnexpectedValueException;
+use Wikibase\DataModel\Entity\EntityIdParsingException;
+use Countable;
+use Wikibase\DataModel\Entity\EntityIdValue;
 use WikidataQuality\ExternalValidation\CheckForCrossCheckViolationsJob;
 use 
WikidataQuality\ExternalValidation\CrossCheck\Comparer\DataValueComparerFactory;
 use WikidataQuality\ExternalValidation\CrossCheck\CrossChecker;
@@ -18,18 +33,88 @@
 use 
WikidataQuality\ExternalValidation\DumpMetaInformation\DumpMetaInformationLookup;
 use WikidataQuality\Html\HtmlTable;
 use WikidataQuality\Html\HtmlTableHeader;
-use WikidataQuality\Specials\SpecialCheckResultPage;
 
 
-class SpecialCrossCheck extends SpecialCheckResultPage {
+class SpecialCrossCheck extends SpecialPage {
 
     /**
      * @var CrossCheckInteractor
      */
     private $crossCheckInteractor;
 
-    public function __construct() {
-        parent::__construct( 'CrossCheck' );
+    /**
+     * @var \Wikibase\DataModel\Entity\EntityIdParser
+     */
+    protected $entityIdParser;
+
+    /**
+     * @var \Wikibase\Lib\Store\EntityLookup
+     */
+    protected $entityLookup;
+
+    /**
+     * @var \ValueFormatters\ValueFormatter
+     */
+    protected $dataValueFormatter;
+
+    /**
+     * @var EntityIdLabelFormatter
+     */
+    protected $entityIdLabelFormatter;
+
+    /**
+     * @var EntityIdLinkFormatter
+     */
+    protected $entityIdLinkFormatter;
+
+    /**
+     * @var EntityIdHtmlLinkFormatter
+     */
+    protected $entityIdHtmlLinkFormatter;
+
+    /**
+     * @var HtmlUrlFormatter
+     */
+    protected $htmlUrlFormatter;
+
+    /**
+     * @param string $name
+     * @param string $restriction
+     * @param bool $listed
+     * @param bool $function
+     * @param string $file
+     * @param bool $includable
+     */
+    public function __construct( $name = 'CrossCheck', $restriction = '', 
$listed = true, $function = false, $file = '', $includable = false ) {
+        parent::__construct( $name, $restriction, $listed, $function, $file, 
$includable );
+
+        $repo = WikibaseRepo::getDefaultInstance();
+
+        // Get entity lookup
+        $this->entityLookup = $repo->getEntityLookup();
+
+        // Get entity id parser
+        $this->entityIdParser = $repo->getEntityIdParser();
+
+        // Get value formatter
+        $formatterOptions = new FormatterOptions();
+        $formatterOptions->setOption( SnakFormatter::OPT_LANG, 
$this->getLanguage()->getCode() );
+        $this->dataValueFormatter = 
$repo->getValueFormatterFactory()->getValueFormatter( 
SnakFormatter::FORMAT_HTML, $formatterOptions );
+
+        // Get entity id link formatters
+        $entityTitleLookup = $repo->getEntityTitleLookup();
+        $labelLookup = new LanguageLabelDescriptionLookup( 
$repo->getTermLookup(), $this->getLanguage()->getCode() );
+        $this->entityIdLabelFormatter = new EntityIdLabelFormatter( 
$labelLookup );
+        $this->entityIdLinkFormatter = new EntityIdLinkFormatter( 
$entityTitleLookup );
+        $this->entityIdHtmlLinkFormatter = new EntityIdHtmlLinkFormatter(
+            $labelLookup,
+            $entityTitleLookup,
+            new LanguageNameLookup()
+        );
+
+        // Get url formatter
+        $formatterOptions = new FormatterOptions();
+        $this->htmlUrlFormatter = new HtmlUrlFormatter( $formatterOptions );
 
         $claimGuidParser = 
WikibaseRepo::getDefaultInstance()->getClaimGuidParser();
         $dataValueComparerFactory = new DataValueComparerFactory( 
$this->entityLookup );
@@ -43,6 +128,25 @@
             $claimGuidParser,
             $crossChecker
         );
+    }
+
+    /**
+     * Returns array of modules that should be added
+     *
+     * @return array
+     */
+    protected function getModules() {
+        return array ( 'SpecialExternalValidationPage' );
+    }
+
+
+    /**
+     * @see SpecialPage::getGroupName
+     *
+     * @return string
+     */
+    function getGroupName() {
+        return 'wikidataquality';
     }
 
     /**
@@ -89,6 +193,302 @@
         $this->doEvaluation( $entity, $results );
 
         return $results;
+    }
+
+    /**
+     * @see SpecialPage::execute
+     *
+     * @param string|null $subPage
+     */
+    public function execute( $subPage ) {
+        $out = $this->getOutput();
+
+        $postRequest = $this->getContext()->getRequest()->getVal( 'entityId' );
+        if ( $postRequest ) {
+            $out->redirect( $this->getPageTitle( strtoupper( $postRequest ) 
)->getLocalURL() );
+            return;
+        }
+
+        $out->addModules( $this->getModules() );
+
+        $this->setHeaders();
+
+        $out->addHTML(
+            $this->getInstructionsText()
+            . $this->buildEntityIdForm()
+        );
+
+        if ( !$subPage ) {
+            return;
+        }
+
+        if ( !is_string( $subPage ) ) {
+            throw new InvalidArgumentException( '$subPage must be string.' );
+        }
+
+        try {
+            $entityId = $this->entityIdParser->parse( $subPage );
+            $entity = $this->entityLookup->getEntity( $entityId );
+        } catch ( EntityIdParsingException $e ) {
+            $out->addHTML(
+                $this->buildNotice( $this->msg( 
'wikidataquality-checkresult-invalid-entity-id' )->text(), true )
+            );
+            return;
+        }
+
+        if ( !$entity ) {
+            $out->addHTML(
+                $this->buildNotice( $this->msg( 
'wikidataquality-checkresult-not-existent-entity' )->text(), true )
+            );
+            return;
+        }
+
+        $results = $this->executeCheck( $entity );
+
+        if ( !is_array( $results ) ) {
+            if ( !( $results instanceof Traversable && $results instanceof 
Countable ) ) {
+                throw new UnexpectedValueException( 
'SpecialCheckResultPage::executeCheck has to return an array or traversable and 
countable object.' );
+            }
+        }
+
+        if ( $results && count( $results ) > 0 ) {
+            $out->addHTML(
+                $this->buildResultHeader( $entityId )
+                . $this->buildSummary( $results )
+                . $this->buildResultTable( $entityId, $results )
+            );
+        } else {
+            $out->addHTML(
+                $this->buildResultHeader( $entityId )
+                . $this->buildNotice( $this->getEmptyResultText() )
+            );
+        }
+    }
+
+    /**
+     * Returns html text of the entity id form
+     *
+     * @return string
+     */
+    protected function buildEntityIdForm() {
+        return
+            Html::openElement(
+                'form',
+                array (
+                    'class' => 'wbq-checkresult-form',
+                    'action' => $this->getPageTitle()->getLocalURL(),
+                    'method' => 'post'
+                )
+            )
+            . Html::input(
+                'entityId',
+                '',
+                'text',
+                array (
+                    'class' => 'wbq-checkresult-form-entity-id',
+                    'placeholder' => $this->msg( 
'wikidataquality-checkresult-form-entityid-placeholder' )->text()
+                )
+            )
+            . Html::input(
+                'submit',
+                $this->msg( 'wikidataquality-checkresult-form-submit-label' 
)->text(),
+                'submit',
+                array (
+                    'class' => 'wbq-checkresult-form-submit'
+                )
+            )
+            . Html::closeElement( 'form' );
+    }
+
+    /**
+     * Builds notice with given message. Optionally notice can be handles as 
error by settings $error to true
+     *
+     * @param string $message
+     * @param bool $error
+     *
+     * @return string
+     */
+    protected function buildNotice( $message, $error = false ) {
+        if ( !is_string( $message ) ) {
+            throw new InvalidArgumentException( '$message must be string.' );
+        }
+        if ( !is_bool( $error ) ) {
+            throw new InvalidArgumentException( '$error must be bool.' );
+        }
+
+        $cssClasses = 'wbq-checkresult-notice';
+        if ( $error ) {
+            $cssClasses .= ' wbq-checkresult-notice-error';
+        }
+
+        return
+            Html::element(
+                'p',
+                array (
+                    'class' => $cssClasses
+                ),
+                $message );
+    }
+
+    /**
+     * Returns html text of the result header
+     *
+     * @param EntityId $entityId
+     *
+     * @return string
+     */
+    protected function buildResultHeader( EntityId $entityId ) {
+        $entityLink = sprintf( '%s (%s)',
+                               
$this->entityIdHtmlLinkFormatter->formatEntityId( $entityId ),
+                               $entityId->getSerialization() );
+
+        return
+            Html::openElement( 'h3' )
+            . $this->msg( 'wikidataquality-checkresult-result-headline', 
$entityLink )->text()
+            . Html::closeElement( 'h3' );
+    }
+
+    /**
+     * Builds summary from given results
+     *
+     * @param array|Traversable $results
+     *
+     * @return string
+     */
+    protected function buildSummary( $results ) {
+        $statuses = array ();
+        foreach ( $results as $result ) {
+            $status = strtolower( $result->getStatus() );
+            if ( array_key_exists( $status, $statuses ) ) {
+                $statuses[ $status ]++;
+            } else {
+                $statuses[ $status ] = 1;
+            }
+        }
+
+        $statusElements = array ();
+        foreach ( $statuses as $status => $count ) {
+            if ( $count > 0 ) {
+                $statusElements[ ] =
+                    $this->formatStatus( $status )
+                    . ": "
+                    . $count;
+            }
+        }
+        $summary =
+            Html::openElement( 'p' )
+            . implode( ', ', $statusElements )
+            . Html::closeElement( 'p' );
+
+        return $summary;
+    }
+
+    /**
+     * Builds a html div element with given content and a tooltip with given 
tooltip content
+     * If $tooltipContent is null, no tooltip will be created
+     *
+     * @param string $content
+     * @param string $tooltipContent
+     *
+     * @return string
+     */
+    protected function buildTooltipElement( $content, $tooltipContent ) {
+        if ( !is_string( $content ) ) {
+            throw new InvalidArgumentException( '$content has to be string.' );
+        }
+        if ( $tooltipContent && ( !is_string( $tooltipContent ) ) ) {
+            throw new InvalidArgumentException( '$tooltipContent, if provided, 
has to be string.' );
+        }
+
+        if ( empty( $tooltipContent ) ) {
+            return $content;
+        }
+
+        $tooltipIndicator = Html::element(
+            'span',
+            array (
+                'class' => 'wbq-tooltip-indicator'
+            )
+        );
+
+        return
+            Html::openElement(
+                'span',
+                array (
+                    'tooltip' => $tooltipContent
+                )
+            )
+            . sprintf( '%s %s', $content, $tooltipIndicator )
+            . Html::closeElement( 'span' );
+    }
+
+    /**
+     * Formats given status to html
+     *
+     * @param string $status
+     *
+     * @return string
+     */
+    protected function formatStatus( $status ) {
+        if ( !is_string( $status ) ) {
+            throw new InvalidArgumentException( '$status has to be string.' );
+        }
+
+        $messageName = "wikidataquality-checkresult-status-" . strtolower( 
$status );
+        $message = $this->msg( $messageName )->text();
+
+        $statusMapping = $this->getStatusMapping();
+        if ( array_key_exists( $status, $statusMapping ) ) {
+            $genericStatus = $statusMapping[ $status ];
+        } else {
+            $genericStatus = 'unknown';
+        }
+
+        $formattedStatus =
+            Html::element(
+                'span',
+                array (
+                    'class' => 'wbq-status wbq-status-' . $genericStatus
+                ),
+                $message
+            );
+
+        return $formattedStatus;
+    }
+
+    /**
+     * Parses data values to human-readable string
+     *
+     * @param DataValue|array $dataValues
+     * @param bool $linking
+     * @param string $separator
+     *
+     * @return string
+     */
+    protected function formatDataValues( $dataValues, $linking = true, 
$separator = ', ' ) {
+        if ( $dataValues instanceof DataValue ) {
+            $dataValues = array ( $dataValues );
+        } elseif ( !is_array( $dataValues ) ) {
+            throw new InvalidArgumentException( '$dataValues has to be 
instance of DataValue or an array of DataValues.' );
+        }
+
+        $formattedDataValues = array ();
+        foreach ( $dataValues as $dataValue ) {
+            if ( !( $dataValue instanceof DataValue ) ) {
+                throw new InvalidArgumentException( '$dataValues has to be 
instance of DataValue or an array of DataValues.' );
+            }
+            if ( $dataValue instanceof EntityIdValue ) {
+                if ( $linking ) {
+                    $formattedDataValues[ ] = 
$this->entityIdHtmlLinkFormatter->formatEntityId( $dataValue->getEntityId() );
+                } else {
+                    $formattedDataValues[ ] = 
$this->entityIdLabelFormatter->formatEntityId( $dataValue->getEntityId() );
+                }
+            } else {
+                $formattedDataValues[ ] = $this->dataValueFormatter->format( 
$dataValue );
+            }
+        }
+
+        return implode( $separator, $formattedDataValues );
     }
 
     /**
@@ -156,14 +556,11 @@
     }
 
     protected function doEvaluation( $entity, $results ) {
-        //TODO: Push (deferred) job(s) in queue
         $checkTimeStamp = wfTimestamp( TS_MW );
         $jobs = array();
         $jobs[] = CheckForCrossCheckViolationsJob::newInsertNow( $entity, 
$checkTimeStamp, $results );
         $jobs[] = CheckForCrossCheckViolationsJob::newInsertDeferred( $entity, 
$checkTimeStamp, 10 );
 
-        $jobs[0]->run();
-        $jobs[1]->run();
         JobQueueGroup::singleton()->push( $jobs );
     }
 }
diff --git a/specials/SpecialExternalDbs.php b/specials/SpecialExternalDbs.php
index 36ab57a..488726a 100755
--- a/specials/SpecialExternalDbs.php
+++ b/specials/SpecialExternalDbs.php
@@ -2,6 +2,17 @@
 
 namespace WikidataQuality\ExternalValidation\Specials;
 
+
+use SpecialPage;
+use ValueFormatters\FormatterOptions;
+use Wikibase\Lib\EntityIdLabelFormatter;
+use Wikibase\Lib\EntityIdHtmlLinkFormatter;
+use Wikibase\Lib\EntityIdLinkFormatter;
+use Wikibase\Lib\HtmlUrlFormatter;
+use Wikibase\Lib\LanguageNameLookup;
+use Wikibase\Lib\SnakFormatter;
+use Wikibase\Lib\Store\LanguageLabelDescriptionLookup;
+use Wikibase\Repo\WikibaseRepo;
 use DateInterval;
 use DateTimeZone;
 use Html;
@@ -11,14 +22,93 @@
 use 
WikidataQuality\ExternalValidation\DumpMetaInformation\DumpMetaInformationLookup;
 use WikidataQuality\Html\HtmlTable;
 use WikidataQuality\Html\HtmlTableCell;
-use WikidataQuality\Specials\SpecialWikidataQualityPage;
 use DateTime;
 
 
-class SpecialExternalDbs extends SpecialWikidataQualityPage {
+class SpecialExternalDbs extends SpecialPage {
 
-       public function __construct() {
-               parent::__construct( 'ExternalDbs' );
+       /**
+        * @var \Wikibase\DataModel\Entity\EntityIdParser
+        */
+       protected $entityIdParser;
+
+       /**
+        * @var \Wikibase\Lib\Store\EntityLookup
+        */
+       protected $entityLookup;
+
+       /**
+        * @var \ValueFormatters\ValueFormatter
+        */
+       protected $dataValueFormatter;
+
+       /**
+        * @var EntityIdLabelFormatter
+        */
+       protected $entityIdLabelFormatter;
+
+       /**
+        * @var EntityIdLinkFormatter
+        */
+       protected $entityIdLinkFormatter;
+
+       /**
+        * @var EntityIdHtmlLinkFormatter
+        */
+       protected $entityIdHtmlLinkFormatter;
+
+       /**
+        * @var HtmlUrlFormatter
+        */
+       protected $htmlUrlFormatter;
+
+       /**
+        * @param string $name
+        * @param string $restriction
+        * @param bool $listed
+        * @param bool $function
+        * @param string $file
+        * @param bool $includable
+        */
+       public function __construct( $name = 'ExternalDbs', $restriction = '', 
$listed = true, $function = false, $file = '', $includable = false ) {
+               parent::__construct( $name, $restriction, $listed, $function, 
$file, $includable );
+
+               $repo = WikibaseRepo::getDefaultInstance();
+
+               // Get entity lookup
+               $this->entityLookup = $repo->getEntityLookup();
+
+               // Get entity id parser
+               $this->entityIdParser = $repo->getEntityIdParser();
+
+               // Get value formatter
+               $formatterOptions = new FormatterOptions();
+               $formatterOptions->setOption( SnakFormatter::OPT_LANG, 
$this->getLanguage()->getCode() );
+               $this->dataValueFormatter = 
$repo->getValueFormatterFactory()->getValueFormatter( 
SnakFormatter::FORMAT_HTML, $formatterOptions );
+
+               // Get entity id link formatters
+               $entityTitleLookup = $repo->getEntityTitleLookup();
+               $labelLookup = new LanguageLabelDescriptionLookup( 
$repo->getTermLookup(), $this->getLanguage()->getCode() );
+               $this->entityIdLabelFormatter = new EntityIdLabelFormatter( 
$labelLookup );
+               $this->entityIdLinkFormatter = new EntityIdLinkFormatter( 
$entityTitleLookup );
+               $this->entityIdHtmlLinkFormatter = new 
EntityIdHtmlLinkFormatter(
+                       $labelLookup,
+                       $entityTitleLookup,
+                       new LanguageNameLookup()
+               );
+
+               // Get url formatter
+               $formatterOptions = new FormatterOptions();
+               $this->htmlUrlFormatter = new HtmlUrlFormatter( 
$formatterOptions );
+       }
+
+       /**
+        * @see SpecialPage::getGroupName
+        *
+        * @return string
+        */
+       function getGroupName() {
+               return 'wikidataquality';
        }
 
        /**

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I601c334f8faaa4651db6f21ba6f1ebaba4eeb27f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/WikidataQualityExternalValidation
Gerrit-Branch: v1
Gerrit-Owner: Jonaskeutel <jonas.keu...@student.hpi.de>
Gerrit-Reviewer: Dominic.sauer <dominic.sa...@yahoo.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to