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