Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 132
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialNewFiles
0.00% covered (danger)
0.00%
0 / 131
0.00% covered (danger)
0.00%
0 / 5
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
72
 buildForm
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
6
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setTopText
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
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
21namespace MediaWiki\Specials;
22
23use MediaWiki\Cache\LinkBatchFactory;
24use MediaWiki\Context\DerivativeContext;
25use MediaWiki\Context\IContextSource;
26use MediaWiki\Html\FormOptions;
27use MediaWiki\Html\Html;
28use MediaWiki\HTMLForm\Field\HTMLUserTextField;
29use MediaWiki\HTMLForm\HTMLForm;
30use MediaWiki\Pager\NewFilesPager;
31use MediaWiki\Permissions\GroupPermissionsLookup;
32use MediaWiki\Request\DerivativeRequest;
33use MediaWiki\SpecialPage\IncludableSpecialPage;
34use MimeAnalyzer;
35use Wikimedia\Rdbms\IConnectionProvider;
36
37/**
38 * Implements Special:Newimages
39 *
40 * @ingroup SpecialPage
41 */
42class 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 */
264class_alias( SpecialNewFiles::class, 'SpecialNewFiles' );