Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 190
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialUploadResult
0.00% covered (danger)
0.00%
0 / 190
0.00% covered (danger)
0.00%
0 / 12
1056
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 formatErrors
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
12
 printRunSelector
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
12
 runSelectorFilter
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 runValidatorFilter
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 runFileCheck
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 processInput
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 printResultRow
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 displayFeedback
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
20
 displayFormulaFeedback
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
20
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3use MediaWiki\MediaWikiServices;
4
5/**
6 * Lets the user import a CSV file with the results
7 *
8 * @author Moritz Schubotz
9 * @author Yaron Koren (This class is based on DT_ImportCSV from the DataTransfer extension)
10 */
11class SpecialUploadResult extends SpecialPage {
12
13    /** @var ImportCsv */
14    private $importer;
15    /** @var bool|int|string */
16    protected $runId = false;
17
18    /**
19     * @param string $name
20     */
21    public function __construct( $name = 'MathUpload' ) {
22        $listed = (bool)$this->getConfig()->get( 'MathWmcServer' );
23        parent::__construct( $name, 'mathwmcsubmit', $listed );
24    }
25
26    /**
27     * @param string[] $errors
28     *
29     * @return string
30     */
31    private static function formatErrors( $errors ) {
32        return wfMessage( 'math-wmc-Warnings' )->text() . "<br />" . implode( "<br />", $errors );
33    }
34
35    /**
36     * @param null|string $query
37     *
38     * @throws PermissionsError
39     */
40    function execute( $query ) {
41        $this->setHeaders();
42        if ( !$this->getUser()->isAllowed( 'mathwmcsubmit' ) ||
43            !$this->getConfig()->get( 'MathUploadEnabled' )
44        ) {
45            throw new PermissionsError( 'mathwmcsubmit' );
46        }
47
48        $this->getOutput()->addWikiTextAsInterface( $this->msg( 'math-wmc-Introduction' )->text() );
49        $this->importer = new ImportCsv( $this->getUser() );
50        $formDescriptor = $this->printRunSelector();
51        $formDescriptor['File'] = [
52            'label-message' => 'math-wmc-FileLabel',
53            'help-message' => 'math-wmc-FileHelp',
54            'class' => 'HTMLTextField',
55            'type' => 'file',
56            'required' => true,
57            'validation-callback' => [ $this, 'runFileCheck' ],
58        ];
59        $formDescriptor['displayFormulae'] = [
60            'label-message' => 'math-wmc-display-formulae-label',
61            'help-message' => 'math-wmc-display-formulae-help',
62            'type' => 'check',
63        ];
64        $formDescriptor['attachResults'] = [
65            'label-message' => 'math-wmc-attach-results-label',
66            'help-message' => 'math-wmc-attach-results-help',
67            'type' => 'check',
68        ];
69        $htmlForm = new HTMLForm( $formDescriptor, $this->getContext() );
70        $htmlForm->setSubmitCallback( [ $this, 'processInput' ] );
71        $htmlForm->show();
72    }
73
74    /**
75     * @param string $type
76     *
77     * @return array
78     */
79    protected function printRunSelector( $type = 'selectorother' ) {
80        // If $wgMathWmcServer is unset there's no math_wmc_runs table to query
81        if ( !$this->getConfig()->get( 'MathWmcServer' ) ) {
82            return [];
83        }
84
85        $dbr = MediaWikiServices::getInstance()
86            ->getConnectionProvider()
87            ->getReplicaDatabase();
88        $formFields = [];
89        $options = [];
90        $uID = $this->getUser()->getId();
91        $res = $dbr->select( 'math_wmc_runs', [ 'runName', 'runId' ],
92            [ 'isDraft' => true, 'userID' => $uID ] );
93        foreach ( $res as $row ) {
94            $options[ $row->runName . " (" . $row->runId . ")" ] = $row->runId;
95        }
96        // Probably we want to add more fields in the future
97        $formFields['run'] = [
98            'type' => $type,
99            'label-message' => 'math-wmc-SelectRun',
100            'options' => $options,
101            'required' => true,
102            'help-message' => 'math-wmc-SelectRunHelp',
103            'filter-callback' => [ $this, 'runSelectorFilter' ],
104            'validation-callback' => [ $this, 'runValidatorFilter' ],
105            // 'section' => 'math-wmc-SectionRun'
106        ];
107        return $formFields;
108    }
109
110    /**
111     * @param string $run
112     *
113     * @return bool|int|string
114     */
115    function runSelectorFilter( $run ) {
116        if ( $run == '' ) {
117            return date( 'Y-m-d H:i:s (e)' );
118        }
119        $this->runId = $this->importer->validateRunId( $run );
120        $warnings = $this->importer->getWarnings();
121        if ( $warnings ) {
122            echo "bad wqarni";
123            foreach ( $warnings as $warning ) {
124                $this->getOutput()->addWikiTextAsInterface( $warning );
125            }
126        }
127        return $run;
128    }
129
130    /**
131     * @return bool|string
132     */
133    function runValidatorFilter() {
134        $dbr = MediaWikiServices::getInstance()
135            ->getConnectionProvider()
136            ->getReplicaDatabase();
137        $uID = $this->getUser()->getId();
138        $res = $dbr->selectField( 'math_wmc_runs', 'runName',
139            [ 'isDraft' => true, 'userID' => $uID, 'runId' => $this->runId ] );
140        if ( !$res ) {
141            return $this->msg( 'math-wmc-SelectRunHelp' )->text();
142        } else {
143            return true;
144        }
145    }
146
147    /**
148     * @return bool|null|string
149     */
150    function runFileCheck() {
151        $out = $this->getOutput();
152
153        $uploadResult = ImportStreamSource::newFromUpload( 'wpFile' );
154
155        if ( !$uploadResult->isOK() ) {
156            return $uploadResult->getWikiText();
157        }
158
159        /** @var ImportStreamSource $source */
160        $source = $uploadResult->value;
161
162        $out->addWikiMsg( 'math-wmc-importing' );
163        // FIXME: ImportStreamSource::$mHandle is private!
164        $error_msg = $this->importer->importFromFile( $source->mHandle );
165
166        if ( $error_msg !== null ) {
167            return $error_msg;
168        }
169        if ( count( $this->importer->getWarnings() ) ) {
170            $out->addWikiTextAsInterface( self::formatErrors( $this->importer->getWarnings() ) );
171        }
172
173        return true;
174    }
175
176    /**
177     * @return bool
178     */
179    function processInput() {
180        $this->getOutput()->addWikiMsg( "math-wmc-SubmissionSuccess" );
181        $this->importer->setOverwrite( !$this->getRequest()->getBool( "wpattachResults" ) );
182        $this->importer->processInput();
183        // TODO: Find adequate API call
184        $this->getOutput()->addHTML( '<table border="1" style="width:100%">
185  <tr>
186    <th>queryId</th>
187    <th>formulaId</th>
188    <th>rank</th>
189    <th>rendering</th>
190  </tr>' );
191        foreach ( $this->importer->getResults() as $result ) {
192            $this->printResultRow( $result );
193        }
194        $this->getOutput()->addHTML( '</table>' );
195        $this->displayFeedback();
196        return true;
197    }
198
199    /**
200     * @param array $row
201     */
202    private function printResultRow( $row ) {
203        $md5 = MathObject::hash2md5( $row['math_inputhash'] );
204        if ( $this->getRequest()->getBool( "wpdisplayFormulae" ) ) {
205            $this->getOutput()->addModuleStyles( [ 'ext.math.styles' ] );
206            $renderer = MediaWikiServices::getInstance()
207                ->get( 'Math.RendererFactory' )
208                ->getFromHash( $md5 );
209            if ( $renderer->render() ) {
210                $renderedMath = $renderer->getHtmlOutput();
211            } else {
212                $renderedMath = $md5;
213            }
214        } else {
215            $renderedMath = $md5;
216        }
217        $formulaId = MathSearchHooks::generateMathAnchorString( $row['oldId'], $row['fId'] );
218        $revisionRecord = MediaWikiServices::getInstance()
219            ->getRevisionLookup()
220            ->getRevisionById( $row['oldId'] );
221        $title = Title::newFromLinkTarget( $revisionRecord->getPageAsLinkTarget() );
222        $link = $title->getLinkURL() . $formulaId;
223        $this->getOutput()->addHTML( "<tr><td>{$row['qId']}</td><td><a href=\"$link\" >$formulaId</a></td>
224            <td>{$row['rank']}</td><td>$renderedMath</td></tr>" );
225    }
226
227    private function displayFeedback() {
228        $runId = $this->runId;
229        $dbr = MediaWikiServices::getInstance()
230            ->getConnectionProvider()
231            ->getReplicaDatabase();
232        $res = $dbr->select(
233            [ 'l' => 'math_wmc_rank_levels', 'r' => 'math_wmc_ref', 'math_wmc_results' ],
234            [
235                'count(DISTINCT `r`.`qId`)  AS `c`',
236                '`l`.`level`                AS `level`'
237            ],
238            [
239                "(`math_wmc_results`.`rank` <= `l`.`level`)",
240                'runId' => $runId,
241                '`math_wmc_results`.`oldId` = `r`.`oldId`',
242                '`math_wmc_results`.`qId` = `r`.`qId`'
243            ],
244            __METHOD__,
245            [
246                'GROUP BY' => '`l`.`level`',
247                'ORDER BY' => 'count(DISTINCT `r`.`qId`) DESC'
248            ]
249        );
250        if ( !$res || $res->numRows() == 0 ) {
251            $this->getOutput()->addWikiTextAsInterface( "Score is 0. Check your submission" );
252            return;
253        } else {
254            $this->getOutput()->addWikiTextAsInterface(
255                "'''Scored in " . $res->numRows() . " evaluation levels'''"
256            );
257        }
258
259        $this->getOutput()->addHTML( '<table border="1" style="width:100%">
260  <tr>
261    <th>number of correct results</th>
262    <th>rank cutoff</th>
263  </tr>' );
264        foreach ( $res as $result ) {
265            $c = $result->c;
266            $l = $result->level;
267            $this->getOutput()->addHTML( "
268  <tr>
269    <td>$c</td>
270    <td>$l</td>
271  </tr>" );
272        }
273        $this->getOutput()->addHTML( '</table>' );
274    }
275
276    private function displayFormulaFeedback() {
277        $runId = $this->runId;
278        $dbr = MediaWikiServices::getInstance()
279            ->getConnectionProvider()
280            ->getReplicaDatabase();
281        $res = $dbr->select(
282            [ 'l' => 'math_wmc_rank_levels', 'r' => 'math_wmc_ref', 'math_wmc_results' ],
283            [
284                'count(DISTINCT `r`.`qId`)  AS `c`',
285                '`l`.`level`                AS `level`'
286            ],
287            [
288                "(`math_wmc_results`.`rank` <= `l`.`level`)",
289                'runId' => $runId,
290                '`math_wmc_results`.`oldId` = `r`.`oldId`',
291                '`math_wmc_results`.`qId` = `r`.`qId`',
292                '`math_wmc_results`.`fId` = `r`.`fId`',
293            ],
294            __METHOD__,
295            [
296                'GROUP BY' => '`l`.`level`',
297                'ORDER BY' => 'count(DISTINCT `r`.`qId`) DESC'
298            ]
299        );
300        if ( !$res || $res->numRows() == 0 ) {
301            $this->getOutput()->addWikiTextAsInterface( "Score is 0. Check your submission" );
302            return;
303        } else {
304            $this->getOutput()->addWikiTextAsInterface(
305                "'''Scored in " . $res->numRows() . " evaluation levels'''"
306            );
307        }
308
309        $this->getOutput()->addHTML( '<table border="1" style="width:100%">
310  <tr>
311    <th>number of correct results</th>
312    <th>rank cutoff</th>
313  </tr>' );
314        foreach ( $res as $result ) {
315            $c = $result->c;
316            $l = $result->level;
317            $this->getOutput()->addHTML( "
318  <tr>
319    <td>$c</td>
320    <td>$l</td>
321  </tr>" );
322        }
323        $this->getOutput()->addHTML( '</table>' );
324    }
325
326    protected function getGroupName() {
327        return 'mathsearch';
328    }
329}