Completed
Branch master (939199)
by
unknown
39:35
created

includes/page/ImageHistoryList.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
/**
22
 * Builds the image revision log shown on image pages
23
 *
24
 * @ingroup Media
25
 */
26
class ImageHistoryList extends ContextSource {
27
28
	/**
29
	 * @var Title
30
	 */
31
	protected $title;
32
33
	/**
34
	 * @var File
35
	 */
36
	protected $img;
37
38
	/**
39
	 * @var ImagePage
40
	 */
41
	protected $imagePage;
42
43
	/**
44
	 * @var File
45
	 */
46
	protected $current;
47
48
	protected $repo, $showThumb;
0 ignored issues
show
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
49
	protected $preventClickjacking = false;
50
51
	/**
52
	 * @param ImagePage $imagePage
53
	 */
54
	public function __construct( $imagePage ) {
55
		global $wgShowArchiveThumbnails;
56
		$this->current = $imagePage->getPage()->getFile();
57
		$this->img = $imagePage->getDisplayedFile();
58
		$this->title = $imagePage->getTitle();
59
		$this->imagePage = $imagePage;
60
		$this->showThumb = $wgShowArchiveThumbnails && $this->img->canRender();
61
		$this->setContext( $imagePage->getContext() );
62
	}
63
64
	/**
65
	 * @return ImagePage
66
	 */
67
	public function getImagePage() {
68
		return $this->imagePage;
69
	}
70
71
	/**
72
	 * @return File
73
	 */
74
	public function getFile() {
75
		return $this->img;
76
	}
77
78
	/**
79
	 * @param string $navLinks
80
	 * @return string
81
	 */
82
	public function beginImageHistoryList( $navLinks = '' ) {
83
		return Xml::element( 'h2', [ 'id' => 'filehistory' ], $this->msg( 'filehist' )->text() )
84
		. "\n"
85
		. "<div id=\"mw-imagepage-section-filehistory\">\n"
86
		. $this->msg( 'filehist-help' )->parseAsBlock()
87
		. $navLinks . "\n"
88
		. Xml::openElement( 'table', [ 'class' => 'wikitable filehistory' ] ) . "\n"
89
		. '<tr><th></th>'
90
		. ( $this->current->isLocal()
91
		&& ( $this->getUser()->isAllowedAny( 'delete', 'deletedhistory' ) ) ? '<th></th>' : '' )
92
		. '<th>' . $this->msg( 'filehist-datetime' )->escaped() . '</th>'
93
		. ( $this->showThumb ? '<th>' . $this->msg( 'filehist-thumb' )->escaped() . '</th>' : '' )
94
		. '<th>' . $this->msg( 'filehist-dimensions' )->escaped() . '</th>'
95
		. '<th>' . $this->msg( 'filehist-user' )->escaped() . '</th>'
96
		. '<th>' . $this->msg( 'filehist-comment' )->escaped() . '</th>'
97
		. "</tr>\n";
98
	}
99
100
	/**
101
	 * @param string $navLinks
102
	 * @return string
103
	 */
104
	public function endImageHistoryList( $navLinks = '' ) {
105
		return "</table>\n$navLinks\n</div>\n";
106
	}
107
108
	/**
109
	 * @param bool $iscur
110
	 * @param File $file
111
	 * @return string
112
	 */
113
	public function imageHistoryLine( $iscur, $file ) {
114
		global $wgContLang;
115
116
		$user = $this->getUser();
117
		$lang = $this->getLanguage();
118
		$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
119
		$img = $iscur ? $file->getName() : $file->getArchiveName();
120
		$userId = $file->getUser( 'id' );
121
		$userText = $file->getUser( 'text' );
122
		$description = $file->getDescription( File::FOR_THIS_USER, $user );
123
124
		$local = $this->current->isLocal();
125
		$row = $selected = '';
126
127
		// Deletion link
128
		if ( $local && ( $user->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
129
			$row .= '<td>';
130
			# Link to remove from history
131
			if ( $user->isAllowed( 'delete' ) ) {
132
				$q = [ 'action' => 'delete' ];
133
				if ( !$iscur ) {
134
					$q['oldimage'] = $img;
135
				}
136
				$row .= Linker::linkKnown(
137
					$this->title,
138
					$this->msg( $iscur ? 'filehist-deleteall' : 'filehist-deleteone' )->escaped(),
139
					[], $q
140
				);
141
			}
142
			# Link to hide content. Don't show useless link to people who cannot hide revisions.
143
			$canHide = $user->isAllowed( 'deleterevision' );
144
			if ( $canHide || ( $user->isAllowed( 'deletedhistory' ) && $file->getVisibility() ) ) {
145
				if ( $user->isAllowed( 'delete' ) ) {
146
					$row .= '<br />';
147
				}
148
				// If file is top revision or locked from this user, don't link
149
				if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
150
					$del = Linker::revDeleteLinkDisabled( $canHide );
151
				} else {
152
					list( $ts, ) = explode( '!', $img, 2 );
153
					$query = [
154
						'type' => 'oldimage',
155
						'target' => $this->title->getPrefixedText(),
156
						'ids' => $ts,
157
					];
158
					$del = Linker::revDeleteLink( $query,
159
						$file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
160
				}
161
				$row .= $del;
162
			}
163
			$row .= '</td>';
164
		}
165
166
		// Reversion link/current indicator
167
		$row .= '<td>';
168
		if ( $iscur ) {
169
			$row .= $this->msg( 'filehist-current' )->escaped();
170
		} elseif ( $local && $this->title->quickUserCan( 'edit', $user )
171
			&& $this->title->quickUserCan( 'upload', $user )
172
		) {
173
			if ( $file->isDeleted( File::DELETED_FILE ) ) {
174
				$row .= $this->msg( 'filehist-revert' )->escaped();
175
			} else {
176
				$row .= Linker::linkKnown(
177
					$this->title,
178
					$this->msg( 'filehist-revert' )->escaped(),
179
					[],
180
					[
181
						'action' => 'revert',
182
						'oldimage' => $img,
183
					]
184
				);
185
			}
186
		}
187
		$row .= '</td>';
188
189
		// Date/time and image link
190
		if ( $file->getTimestamp() === $this->img->getTimestamp() ) {
191
			$selected = "class='filehistory-selected'";
192
		}
193
		$row .= "<td $selected style='white-space: nowrap;'>";
194
		if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
195
			# Don't link to unviewable files
196
			$row .= '<span class="history-deleted">'
197
				. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
198
		} elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
199
			if ( $local ) {
200
				$this->preventClickjacking();
201
				$revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
202
				# Make a link to review the image
203
				$url = Linker::linkKnown(
204
					$revdel,
205
					$lang->userTimeAndDate( $timestamp, $user ),
206
					[],
207
					[
208
						'target' => $this->title->getPrefixedText(),
209
						'file' => $img,
210
						'token' => $user->getEditToken( $img )
211
					]
212
				);
213
			} else {
214
				$url = $lang->userTimeAndDate( $timestamp, $user );
215
			}
216
			$row .= '<span class="history-deleted">' . $url . '</span>';
217
		} elseif ( !$file->exists() ) {
218
			$row .= '<span class="mw-file-missing">'
219
				. $lang->userTimeAndDate( $timestamp, $user ) . '</span>';
220
		} else {
221
			$url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
222
			$row .= Xml::element(
223
				'a',
224
				[ 'href' => $url ],
225
				$lang->userTimeAndDate( $timestamp, $user )
226
			);
227
		}
228
		$row .= "</td>";
229
230
		// Thumbnail
231
		if ( $this->showThumb ) {
232
			$row .= '<td>' . $this->getThumbForLine( $file ) . '</td>';
233
		}
234
235
		// Image dimensions + size
236
		$row .= '<td>';
237
		$row .= htmlspecialchars( $file->getDimensionsString() );
238
		$row .= $this->msg( 'word-separator' )->escaped();
239
		$row .= '<span style="white-space: nowrap;">';
240
		$row .= $this->msg( 'parentheses' )->sizeParams( $file->getSize() )->escaped();
241
		$row .= '</span>';
242
		$row .= '</td>';
243
244
		// Uploading user
245
		$row .= '<td>';
246
		// Hide deleted usernames
247
		if ( $file->isDeleted( File::DELETED_USER ) ) {
248
			$row .= '<span class="history-deleted">'
249
				. $this->msg( 'rev-deleted-user' )->escaped() . '</span>';
250
		} else {
251
			if ( $local ) {
252
				$row .= Linker::userLink( $userId, $userText );
253
				$row .= '<span style="white-space: nowrap;">';
254
				$row .= Linker::userToolLinks( $userId, $userText );
255
				$row .= '</span>';
256
			} else {
257
				$row .= htmlspecialchars( $userText );
258
			}
259
		}
260
		$row .= '</td>';
261
262
		// Don't show deleted descriptions
263
		if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
264
			$row .= '<td><span class="history-deleted">' .
265
				$this->msg( 'rev-deleted-comment' )->escaped() . '</span></td>';
266
		} else {
267
			$row .= '<td dir="' . $wgContLang->getDir() . '">' .
268
				Linker::formatComment( $description, $this->title ) . '</td>';
269
		}
270
271
		$rowClass = null;
272
		Hooks::run( 'ImagePageFileHistoryLine', [ $this, $file, &$row, &$rowClass ] );
273
		$classAttr = $rowClass ? " class='$rowClass'" : '';
274
275
		return "<tr{$classAttr}>{$row}</tr>\n";
276
	}
277
278
	/**
279
	 * @param File $file
280
	 * @return string
281
	 */
282
	protected function getThumbForLine( $file ) {
283
		$lang = $this->getLanguage();
284
		$user = $this->getUser();
285
		if ( $file->allowInlineDisplay() && $file->userCan( File::DELETED_FILE, $user )
286
			&& !$file->isDeleted( File::DELETED_FILE )
287
		) {
288
			$params = [
289
				'width' => '120',
290
				'height' => '120',
291
			];
292
			$timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
293
294
			$thumbnail = $file->transform( $params );
295
			$options = [
296
				'alt' => $this->msg( 'filehist-thumbtext',
297
					$lang->userTimeAndDate( $timestamp, $user ),
298
					$lang->userDate( $timestamp, $user ),
299
					$lang->userTime( $timestamp, $user ) )->text(),
300
				'file-link' => true,
301
			];
302
303
			if ( !$thumbnail ) {
304
				return $this->msg( 'filehist-nothumb' )->escaped();
305
			}
306
307
			return $thumbnail->toHtml( $options );
308
		} else {
309
			return $this->msg( 'filehist-nothumb' )->escaped();
310
		}
311
	}
312
313
	/**
314
	 * @param bool $enable
315
	 */
316
	protected function preventClickjacking( $enable = true ) {
317
		$this->preventClickjacking = $enable;
318
	}
319
320
	/**
321
	 * @return bool
322
	 */
323
	public function getPreventClickjacking() {
324
		return $this->preventClickjacking;
325
	}
326
}
327