Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 132 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
SpecialNewFiles | |
0.00% |
0 / 131 |
|
0.00% |
0 / 5 |
210 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 53 |
|
0.00% |
0 / 1 |
72 | |||
buildForm | |
0.00% |
0 / 60 |
|
0.00% |
0 / 1 |
6 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setTopText | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Specials; |
22 | |
23 | use MediaWiki\Cache\LinkBatchFactory; |
24 | use MediaWiki\Context\DerivativeContext; |
25 | use MediaWiki\Context\IContextSource; |
26 | use MediaWiki\Html\FormOptions; |
27 | use MediaWiki\Html\Html; |
28 | use MediaWiki\HTMLForm\Field\HTMLUserTextField; |
29 | use MediaWiki\HTMLForm\HTMLForm; |
30 | use MediaWiki\Pager\NewFilesPager; |
31 | use MediaWiki\Permissions\GroupPermissionsLookup; |
32 | use MediaWiki\Request\DerivativeRequest; |
33 | use MediaWiki\SpecialPage\IncludableSpecialPage; |
34 | use Wikimedia\Mime\MimeAnalyzer; |
35 | use Wikimedia\Rdbms\IConnectionProvider; |
36 | |
37 | /** |
38 | * Implements Special:Newimages |
39 | * |
40 | * @ingroup SpecialPage |
41 | */ |
42 | class SpecialNewFiles extends IncludableSpecialPage { |
43 | /** @var FormOptions */ |
44 | protected $opts; |
45 | |
46 | /** @var string[] */ |
47 | protected $mediaTypes; |
48 | |
49 | private GroupPermissionsLookup $groupPermissionsLookup; |
50 | private IConnectionProvider $dbProvider; |
51 | private LinkBatchFactory $linkBatchFactory; |
52 | |
53 | /** |
54 | * @param MimeAnalyzer $mimeAnalyzer |
55 | * @param GroupPermissionsLookup $groupPermissionsLookup |
56 | * @param IConnectionProvider $dbProvider |
57 | * @param LinkBatchFactory $linkBatchFactory |
58 | */ |
59 | public function __construct( |
60 | MimeAnalyzer $mimeAnalyzer, |
61 | GroupPermissionsLookup $groupPermissionsLookup, |
62 | IConnectionProvider $dbProvider, |
63 | LinkBatchFactory $linkBatchFactory |
64 | ) { |
65 | parent::__construct( 'Newimages' ); |
66 | $this->groupPermissionsLookup = $groupPermissionsLookup; |
67 | $this->dbProvider = $dbProvider; |
68 | $this->mediaTypes = $mimeAnalyzer->getMediaTypes(); |
69 | $this->linkBatchFactory = $linkBatchFactory; |
70 | } |
71 | |
72 | public function execute( $par ) { |
73 | $context = new DerivativeContext( $this->getContext() ); |
74 | |
75 | $this->setHeaders(); |
76 | $this->outputHeader(); |
77 | |
78 | $out = $this->getOutput(); |
79 | $this->addHelpLink( 'Help:New images' ); |
80 | |
81 | $opts = new FormOptions(); |
82 | |
83 | $opts->add( 'user', '' ); |
84 | $opts->add( 'showbots', false ); |
85 | $opts->add( 'hidepatrolled', false ); |
86 | $opts->add( 'mediatype', $this->mediaTypes ); |
87 | $opts->add( 'limit', 50 ); |
88 | $opts->add( 'offset', '' ); |
89 | $opts->add( 'start', '' ); |
90 | $opts->add( 'end', '' ); |
91 | |
92 | $opts->fetchValuesFromRequest( $this->getRequest() ); |
93 | |
94 | if ( $par !== null ) { |
95 | $opts->setValue( 'limit', $par ); |
96 | } |
97 | |
98 | // If start date comes after end date chronologically, swap them. |
99 | // They are swapped in the interface by JS. |
100 | $start = $opts->getValue( 'start' ); |
101 | $end = $opts->getValue( 'end' ); |
102 | if ( $start !== '' && $end !== '' && $start > $end ) { |
103 | $temp = $end; |
104 | $end = $start; |
105 | $start = $temp; |
106 | |
107 | $opts->setValue( 'start', $start, true ); |
108 | $opts->setValue( 'end', $end, true ); |
109 | |
110 | // also swap values in request object, which is used by HTMLForm |
111 | // to pre-populate the fields with the previous input |
112 | $request = $context->getRequest(); |
113 | $context->setRequest( new DerivativeRequest( |
114 | $request, |
115 | [ 'start' => $start, 'end' => $end ] + $request->getValues(), |
116 | $request->wasPosted() |
117 | ) ); |
118 | } |
119 | |
120 | // Avoid unexpected query or query errors to assoc array input, or nested arrays via |
121 | // URL query params. Keep only string values (T321133). |
122 | $mediaTypes = $opts->getValue( 'mediatype' ); |
123 | $mediaTypes = array_filter( $mediaTypes, 'is_string' ); |
124 | // Avoid unbounded query size with bogus values. Keep only known types. |
125 | $mediaTypes = array_values( array_intersect( $this->mediaTypes, $mediaTypes ) ); |
126 | // Optimization: Remove redundant IN() query condition if all types are checked. |
127 | if ( !array_diff( $this->mediaTypes, $mediaTypes ) ) { |
128 | $mediaTypes = []; |
129 | } |
130 | $opts->setValue( 'mediatype', $mediaTypes ); |
131 | |
132 | $opts->validateIntBounds( 'limit', 0, 500 ); |
133 | |
134 | $this->opts = $opts; |
135 | |
136 | if ( !$this->including() ) { |
137 | $this->setTopText(); |
138 | $this->buildForm( $context ); |
139 | } |
140 | |
141 | $pager = new NewFilesPager( |
142 | $context, |
143 | $this->groupPermissionsLookup, |
144 | $this->linkBatchFactory, |
145 | $this->getLinkRenderer(), |
146 | $this->dbProvider, |
147 | $opts |
148 | ); |
149 | |
150 | $out->addHTML( $pager->getBody() ); |
151 | if ( !$this->including() ) { |
152 | $out->addHTML( $pager->getNavigationBar() ); |
153 | } |
154 | } |
155 | |
156 | protected function buildForm( IContextSource $context ) { |
157 | $mediaTypesText = array_map( function ( $type ) { |
158 | // mediastatistics-header-unknown, mediastatistics-header-bitmap, |
159 | // mediastatistics-header-drawing, mediastatistics-header-audio, |
160 | // mediastatistics-header-video, mediastatistics-header-multimedia, |
161 | // mediastatistics-header-office, mediastatistics-header-text, |
162 | // mediastatistics-header-executable, mediastatistics-header-archive, |
163 | // mediastatistics-header-3d, |
164 | return $this->msg( 'mediastatistics-header-' . strtolower( $type ) )->escaped(); |
165 | }, $this->mediaTypes ); |
166 | $mediaTypesOptions = array_combine( $mediaTypesText, $this->mediaTypes ); |
167 | ksort( $mediaTypesOptions ); |
168 | |
169 | $formDescriptor = [ |
170 | 'user' => [ |
171 | 'class' => HTMLUserTextField::class, |
172 | 'label-message' => 'newimages-user', |
173 | 'name' => 'user', |
174 | ], |
175 | |
176 | 'showbots' => [ |
177 | 'type' => 'check', |
178 | 'label-message' => 'newimages-showbots', |
179 | 'name' => 'showbots', |
180 | ], |
181 | |
182 | 'hidepatrolled' => [ |
183 | 'type' => 'check', |
184 | 'label-message' => 'newimages-hidepatrolled', |
185 | 'name' => 'hidepatrolled', |
186 | ], |
187 | |
188 | 'mediatype' => [ |
189 | 'type' => 'multiselect', |
190 | 'flatlist' => true, |
191 | 'name' => 'mediatype', |
192 | 'label-message' => 'newimages-mediatype', |
193 | 'options' => $mediaTypesOptions, |
194 | 'default' => $this->mediaTypes, |
195 | ], |
196 | |
197 | 'limit' => [ |
198 | 'type' => 'hidden', |
199 | 'default' => $this->opts->getValue( 'limit' ), |
200 | 'name' => 'limit', |
201 | ], |
202 | |
203 | 'offset' => [ |
204 | 'type' => 'hidden', |
205 | 'default' => $this->opts->getValue( 'offset' ), |
206 | 'name' => 'offset', |
207 | ], |
208 | |
209 | 'start' => [ |
210 | 'type' => 'date', |
211 | 'label-message' => 'date-range-from', |
212 | 'name' => 'start', |
213 | ], |
214 | |
215 | 'end' => [ |
216 | 'type' => 'date', |
217 | 'label-message' => 'date-range-to', |
218 | 'name' => 'end', |
219 | ], |
220 | ]; |
221 | |
222 | if ( !$this->getUser()->useFilePatrol() ) { |
223 | unset( $formDescriptor['hidepatrolled'] ); |
224 | } |
225 | |
226 | HTMLForm::factory( 'ooui', $formDescriptor, $context ) |
227 | // For the 'multiselect' field values to be preserved on submit |
228 | ->setFormIdentifier( 'specialnewimages' ) |
229 | ->setWrapperLegendMsg( 'newimages-legend' ) |
230 | ->setSubmitTextMsg( 'ilsubmit' ) |
231 | ->setMethod( 'get' ) |
232 | ->prepareForm() |
233 | ->displayForm( false ); |
234 | } |
235 | |
236 | protected function getGroupName() { |
237 | return 'changes'; |
238 | } |
239 | |
240 | /** |
241 | * Send the text to be displayed above the options |
242 | */ |
243 | public function setTopText() { |
244 | $message = $this->msg( 'newimagestext' )->inContentLanguage(); |
245 | if ( !$message->isDisabled() ) { |
246 | $contLang = $this->getContentLanguage(); |
247 | $this->getOutput()->addWikiTextAsContent( |
248 | Html::rawElement( 'div', |
249 | [ |
250 | 'lang' => $contLang->getHtmlCode(), |
251 | 'dir' => $contLang->getDir() |
252 | ], |
253 | "\n" . $message->plain() . "\n" |
254 | ) |
255 | ); |
256 | } |
257 | } |
258 | } |
259 | |
260 | /** |
261 | * Retain the old class name for backwards compatibility. |
262 | * @deprecated since 1.41 |
263 | */ |
264 | class_alias( SpecialNewFiles::class, 'SpecialNewFiles' ); |