Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialORESModels
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 4
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
 getFilterData
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
110
 getFilterLabel
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace ORES\Specials;
4
5use MediaWiki\Html\TemplateParser;
6use MediaWiki\SpecialPage\SpecialPage;
7use ORES\Storage\ModelLookup;
8use ORES\Storage\ThresholdLookup;
9
10class SpecialORESModels extends SpecialPage {
11
12    /** @var ModelLookup */
13    private $modelLookup;
14
15    /** @var ThresholdLookup */
16    private $thresholdLookup;
17
18    public function __construct( ModelLookup $modelLookup, ThresholdLookup $thresholdLookup ) {
19        parent::__construct( 'ORESModels' );
20        $this->modelLookup = $modelLookup;
21        $this->thresholdLookup = $thresholdLookup;
22    }
23
24    public function execute( $subPage = null ) {
25        parent::execute( $subPage );
26        $this->addHelpLink( 'ORES' );
27
28        $models = [];
29        foreach ( $this->modelLookup->getModels() as $modelName => $modelData ) {
30            $filters = $this->getFilterData( $modelName );
31            if ( $filters === false ) {
32                continue;
33            }
34
35            $models[] = [
36                'model' => $modelName,
37                'title' => $this->msg( "ores-rcfilters-$modelName-title" )->text(),
38                'filters' => $filters
39            ];
40        }
41
42        $templateParser = new TemplateParser( dirname( __DIR__ ) . '/templates' );
43        $this->getOutput()->addHTML( $templateParser->processTemplate(
44            'SpecialORESModels',
45            [
46                'models' => $models,
47                'header-filter' => $this->msg( 'ores-specialoresmodels-header-filter' )->text(),
48                'header-thresholdrange' => $this->msg( 'ores-specialoresmodels-header-thresholdrange' )->text(),
49             ]
50        ) );
51        $this->getOutput()->addModuleStyles( 'ext.ores.styles' );
52    }
53
54    private function getFilterData( $modelName ) {
55        $thresholdConfig = $this->getConfig()->get( 'OresFiltersThresholds' );
56        $thresholdData = $this->thresholdLookup->getRawThresholdData( $modelName );
57        $thresholds = $this->thresholdLookup->getThresholds( $modelName );
58        if ( $thresholds === [] || $thresholdData === false ) {
59            return false;
60        }
61        if ( !in_array( $modelName, [ 'damaging', 'goodfaith', 'revertrisklanguageagnostic' ] ) ) {
62            return false;
63        }
64
65        $filters = [];
66        foreach ( $thresholdConfig[$modelName] as $filterName => $filterMinMax ) {
67            if ( $filterMinMax === false ) {
68                continue;
69            }
70
71            $min = isset( $thresholds[$filterName]['min'] ) ?
72                $this->getLanguage()->formatNum( $thresholds[$filterName]['min'] ) :
73                '???';
74            $max = isset( $thresholds[$filterName]['max'] ) ?
75                $this->getLanguage()->formatNum( $thresholds[$filterName]['max'] ) :
76                '???';
77
78            $filters[] = [
79                'name' => $filterName,
80                'label' => $this->getFilterLabel( $modelName, $filterName ),
81                'threshold-min' => $min,
82                'threshold-max' => $max,
83            ];
84        }
85        // Sort the filters we know about in the proper order, put ones we don't know about at the end
86        uasort( $filters, static function ( $a, $b ) {
87            $knownFilters = [ 'likelygood', 'maybebad', 'likelybad', 'verylikelybad' ];
88            $aIndex = array_search( $a['name'], $knownFilters );
89            $bIndex = array_search( $b['name'], $knownFilters );
90            return ( $aIndex !== false ? $aIndex : INF ) <=> ( $bIndex !== false ? $bIndex : INF );
91        } );
92        return $filters;
93    }
94
95    /**
96     * Get the UI label for a filter as it appears in RecentChanges.
97     * @param string $modelName 'damaging' or 'goodfaith'
98     * @param string $filterName 'likelygood', 'maybebad', 'likelybad' or 'verylikelybad'
99     * @return string Filter label (plain text)
100     */
101    private function getFilterLabel( $modelName, $filterName ) {
102        // TODO factor this out in ChangesListHooksHandler
103        $special = [
104            'goodfaith' => [
105                'likelygood' => 'ores-rcfilters-goodfaith-good-label',
106                'likelybad' => 'ores-rcfilters-goodfaith-bad-label',
107            ]
108        ];
109        $msgKey = $special[$modelName][$filterName] ?? "ores-rcfilters-$modelName-$filterName-label";
110        return $this->msg( $msgKey )->text();
111    }
112
113}