1<?php
2/**
3 * Implements Special:Wantedfiles
4 *
5 * Copyright © 2008 Soxred93
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 * @file
23 * @ingroup SpecialPage
24 * @author Soxred93 <soxred93@gmail.com>
25 */
26
27use MediaWiki\Cache\LinkBatchFactory;
28use MediaWiki\MediaWikiServices;
29use Wikimedia\Rdbms\ILoadBalancer;
30
31/**
32 * Querypage that lists the most wanted files
33 *
34 * @ingroup SpecialPage
35 */
36class WantedFilesPage extends WantedQueryPage {
37
38	/** @var RepoGroup */
39	private $repoGroup;
40
41	/**
42	 * @param RepoGroup|string $repoGroup
43	 * @param ILoadBalancer|null $loadBalancer
44	 * @param LinkBatchFactory|null $linkBatchFactory
45	 */
46	public function __construct(
47		$repoGroup,
48		ILoadBalancer $loadBalancer = null,
49		LinkBatchFactory $linkBatchFactory = null
50	) {
51		parent::__construct( is_string( $repoGroup ) ? $repoGroup : 'Wantedfiles' );
52		// This class is extended and therefor fallback to global state - T265301
53		$services = MediaWikiServices::getInstance();
54		$this->repoGroup = $repoGroup instanceof RepoGroup
55			? $repoGroup
56			: $services->getRepoGroup();
57		$this->setDBLoadBalancer( $loadBalancer ?? $services->getDBLoadBalancer() );
58		$this->setLinkBatchFactory( $linkBatchFactory ?? $services->getLinkBatchFactory() );
59	}
60
61	protected function getPageHeader() {
62		# Specifically setting to use "Wanted Files" (NS_MAIN) as title, so as to get what
63		# category would be used on main namespace pages, for those tricky wikipedia
64		# admins who like to do {{#ifeq:{{NAMESPACE}}|foo|bar|....}}.
65		$catMessage = $this->msg( 'broken-file-category' )
66			->title( Title::newFromText( "Wanted Files", NS_MAIN ) )
67			->inContentLanguage();
68
69		if ( !$catMessage->isDisabled() ) {
70			$category = Title::makeTitleSafe( NS_CATEGORY, $catMessage->text() );
71		} else {
72			$category = false;
73		}
74
75		$noForeign = '';
76		if ( !$this->likelyToHaveFalsePositives() ) {
77			// Additional messages for grep:
78			// wantedfiletext-cat-noforeign, wantedfiletext-nocat-noforeign
79			$noForeign = '-noforeign';
80		}
81
82		if ( $category ) {
83			return $this
84				->msg( 'wantedfiletext-cat' . $noForeign )
85				->params( $category->getFullText() )
86				->parseAsBlock();
87		} else {
88			return $this
89				->msg( 'wantedfiletext-nocat' . $noForeign )
90				->parseAsBlock();
91		}
92	}
93
94	/**
95	 * Whether foreign repos are likely to cause false positives
96	 *
97	 * In its own function to allow subclasses to override.
98	 * @see SpecialWantedFilesGUOverride in GlobalUsage extension.
99	 * @since 1.24
100	 * @return bool
101	 */
102	protected function likelyToHaveFalsePositives() {
103		return $this->repoGroup->hasForeignRepos();
104	}
105
106	/**
107	 * KLUGE: The results may contain false positives for files
108	 * that exist e.g. in a shared repo.  Setting this at least
109	 * keeps them from showing up as redlinks in the output, even
110	 * if it doesn't fix the real problem (T8220).
111	 *
112	 * @note could also have existing links here from broken file
113	 * redirects.
114	 * @return bool
115	 */
116	protected function forceExistenceCheck() {
117		return true;
118	}
119
120	/**
121	 * Does the file exist?
122	 *
123	 * Use findFile() so we still think file namespace pages without files
124	 * are missing, but valid file redirects and foreign files are ok.
125	 *
126	 * @param Title $title
127	 * @return bool
128	 */
129	protected function existenceCheck( Title $title ) {
130		return (bool)$this->repoGroup->findFile( $title );
131	}
132
133	public function getQueryInfo() {
134		return [
135			'tables' => [
136				'imagelinks',
137				'page',
138				'redirect',
139				'img1' => 'image',
140				'img2' => 'image',
141			],
142			'fields' => [
143				'namespace' => NS_FILE,
144				'title' => 'il_to',
145				'value' => 'COUNT(*)'
146			],
147			'conds' => [
148				'img1.img_name' => null,
149				// We also need to exclude file redirects
150				'img2.img_name' => null,
151			],
152			'options' => [ 'GROUP BY' => 'il_to' ],
153			'join_conds' => [
154				'img1' => [ 'LEFT JOIN',
155					'il_to = img1.img_name'
156				],
157				'page' => [ 'LEFT JOIN', [
158					'il_to = page_title',
159					'page_namespace' => NS_FILE,
160				] ],
161				'redirect' => [ 'LEFT JOIN', [
162					'page_id = rd_from',
163					'rd_namespace' => NS_FILE,
164					'rd_interwiki' => ''
165				] ],
166				'img2' => [ 'LEFT JOIN',
167					'rd_title = img2.img_name'
168				]
169			]
170		];
171	}
172
173	protected function getGroupName() {
174		return 'maintenance';
175	}
176}
177