Completed
Branch master (771964)
by
unknown
26:13
created

SpecialLog::parseParams()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 15
rs 8.2222
cc 7
eloc 11
nc 4
nop 2
1
<?php
2
/**
3
 * Implements Special:Log
4
 *
5
 * Copyright © 2008 Aaron Schulz
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
 */
25
26
/**
27
 * A special page that lists log entries
28
 *
29
 * @ingroup SpecialPage
30
 */
31
class SpecialLog extends SpecialPage {
32
	public function __construct() {
33
		parent::__construct( 'Log' );
34
	}
35
36
	public function execute( $par ) {
37
		$this->setHeaders();
38
		$this->outputHeader();
39
		$this->getOutput()->addModules( 'mediawiki.userSuggest' );
40
41
		$opts = new FormOptions;
42
		$opts->add( 'type', '' );
43
		$opts->add( 'user', '' );
44
		$opts->add( 'page', '' );
45
		$opts->add( 'pattern', false );
46
		$opts->add( 'year', null, FormOptions::INTNULL );
47
		$opts->add( 'month', null, FormOptions::INTNULL );
48
		$opts->add( 'tagfilter', '' );
49
		$opts->add( 'offset', '' );
50
		$opts->add( 'dir', '' );
51
		$opts->add( 'offender', '' );
52
		$opts->add( 'subtype', '' );
53
54
		// Set values
55
		$opts->fetchValuesFromRequest( $this->getRequest() );
56
		if ( $par !== null ) {
57
			$this->parseParams( $opts, (string)$par );
58
		}
59
60
		# Don't let the user get stuck with a certain date
61
		if ( $opts->getValue( 'offset' ) || $opts->getValue( 'dir' ) == 'prev' ) {
62
			$opts->setValue( 'year', '' );
63
			$opts->setValue( 'month', '' );
64
		}
65
66
		// If the user doesn't have the right permission to view the specific
67
		// log type, throw a PermissionsError
68
		// If the log type is invalid, just show all public logs
69
		$logRestrictions = $this->getConfig()->get( 'LogRestrictions' );
70
		$type = $opts->getValue( 'type' );
71
		if ( !LogPage::isLogType( $type ) ) {
72
			$opts->setValue( 'type', '' );
73
		} elseif ( isset( $logRestrictions[$type] )
74
			&& !$this->getUser()->isAllowed( $logRestrictions[$type] )
75
		) {
76
			throw new PermissionsError( $logRestrictions[$type] );
77
		}
78
79
		# Handle type-specific inputs
80
		$qc = [];
81
		if ( $opts->getValue( 'type' ) == 'suppress' ) {
82
			$offender = User::newFromName( $opts->getValue( 'offender' ), false );
83
			if ( $offender && $offender->getId() > 0 ) {
84
				$qc = [ 'ls_field' => 'target_author_id', 'ls_value' => $offender->getId() ];
85
			} elseif ( $offender && IP::isIPAddress( $offender->getName() ) ) {
86
				$qc = [ 'ls_field' => 'target_author_ip', 'ls_value' => $offender->getName() ];
87
			}
88
		} else {
89
			// Allow extensions to add relations to their search types
90
			Hooks::run(
91
				'SpecialLogAddLogSearchRelations',
92
				[ $opts->getValue( 'type' ), $this->getRequest(), &$qc ]
93
			);
94
		}
95
96
		# Some log types are only for a 'User:' title but we might have been given
97
		# only the username instead of the full title 'User:username'. This part try
98
		# to lookup for a user by that name and eventually fix user input. See bug 1697.
99
		if ( in_array( $opts->getValue( 'type' ), self::getLogTypesOnUser() ) ) {
100
			# ok we have a type of log which expect a user title.
101
			$target = Title::newFromText( $opts->getValue( 'page' ) );
102
			if ( $target && $target->getNamespace() === NS_MAIN ) {
103
				# User forgot to add 'User:', we are adding it for him
104
				$opts->setValue( 'page',
105
					Title::makeTitleSafe( NS_USER, $opts->getValue( 'page' ) )
106
				);
107
			}
108
		}
109
110
		$this->show( $opts, $qc );
111
	}
112
113
	/**
114
	 * List log type for which the target is a user
115
	 * Thus if the given target is in NS_MAIN we can alter it to be an NS_USER
116
	 * Title user instead.
117
	 *
118
	 * @since 1.25
119
	 * @return array
120
	 */
121
	public static function getLogTypesOnUser() {
122
		static $types = null;
123
		if ( $types !== null ) {
124
			return $types;
125
		}
126
		$types = [
127
			'block',
128
			'newusers',
129
			'rights',
130
		];
131
132
		Hooks::run( 'GetLogTypesOnUser', [ &$types ] );
133
		return $types;
134
	}
135
136
	/**
137
	 * Return an array of subpages that this special page will accept.
138
	 *
139
	 * @return string[] subpages
140
	 */
141
	public function getSubpagesForPrefixSearch() {
142
		$subpages = $this->getConfig()->get( 'LogTypes' );
143
		$subpages[] = 'all';
144
		sort( $subpages );
145
		return $subpages;
146
	}
147
148
	private function parseParams( FormOptions $opts, $par ) {
149
		# Get parameters
150
		$parms = explode( '/', ( $par = ( $par !== null ) ? $par : '' ) );
151
		$symsForAll = [ '*', 'all' ];
152
		if ( $parms[0] != '' &&
153
			( in_array( $par, $this->getConfig()->get( 'LogTypes' ) ) || in_array( $par, $symsForAll ) )
154
		) {
155
			$opts->setValue( 'type', $par );
156
		} elseif ( count( $parms ) == 2 ) {
157
			$opts->setValue( 'type', $parms[0] );
158
			$opts->setValue( 'user', $parms[1] );
159
		} elseif ( $par != '' ) {
160
			$opts->setValue( 'user', $par );
161
		}
162
	}
163
164
	private function show( FormOptions $opts, array $extraConds ) {
165
		# Create a LogPager item to get the results and a LogEventsList item to format them...
166
		$loglist = new LogEventsList(
167
			$this->getContext(),
168
			null,
169
			LogEventsList::USE_CHECKBOXES
170
		);
171
172
		$action = '';
173
		// Allow to filter the log by actions
174
		$type = $opts->getValue( 'type' );
175
		if ( $type !== '' ) {
176
			$actions = $this->getConfig()->get( 'ActionFilteredLogs' );
177
			if ( isset( $actions[$type] ) ) {
178
				// log type can be filtered by actions
179
				$loglist->setAllowedActions( array_keys( $actions[$type] ) );
180
				$action = $opts->getValue( 'subtype' );
181
				if ( $action !== '' && isset( $actions[$type][$action] ) ) {
182
					// add condition to query
183
					$extraConds['log_action'] = $actions[$type][$action];
184
				} else {
185
					// no action or invalid action
186
					$action = '';
187
				}
188
			}
189
		}
190
191
		$pager = new LogPager(
192
			$loglist,
193
			$opts->getValue( 'type' ),
194
			$opts->getValue( 'user' ),
195
			$opts->getValue( 'page' ),
196
			$opts->getValue( 'pattern' ),
197
			$extraConds,
198
			$opts->getValue( 'year' ),
199
			$opts->getValue( 'month' ),
200
			$opts->getValue( 'tagfilter' )
201
		);
202
203
		$this->addHeader( $opts->getValue( 'type' ) );
204
205
		# Set relevant user
206
		if ( $pager->getPerformer() ) {
207
			$this->getSkin()->setRelevantUser( User::newFromName( $pager->getPerformer() ) );
0 ignored issues
show
Security Bug introduced by
It seems like \User::newFromName($pager->getPerformer()) targeting User::newFromName() can also be of type false; however, Skin::setRelevantUser() does only seem to accept object<User>, did you maybe forget to handle an error condition?
Loading history...
208
		}
209
210
		# Show form options
211
		$loglist->showOptions(
212
			$pager->getType(),
213
			$opts->getValue( 'user' ),
214
			$pager->getPage(),
0 ignored issues
show
Bug introduced by
It seems like $pager->getPage() targeting LogPager::getPage() can also be of type object<Title>; however, LogEventsList::showOptions() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
215
			$pager->getPattern(),
216
			$pager->getYear(),
0 ignored issues
show
Security Bug introduced by
It seems like $pager->getYear() targeting LogPager::getYear() can also be of type false; however, LogEventsList::showOptions() does only seem to accept integer, did you maybe forget to handle an error condition?
Loading history...
217
			$pager->getMonth(),
0 ignored issues
show
Security Bug introduced by
It seems like $pager->getMonth() targeting LogPager::getMonth() can also be of type false; however, LogEventsList::showOptions() does only seem to accept integer, did you maybe forget to handle an error condition?
Loading history...
218
			$pager->getFilterParams(),
219
			$opts->getValue( 'tagfilter' ),
220
			$action
221
		);
222
223
		# Insert list
224
		$logBody = $pager->getBody();
225
		if ( $logBody ) {
226
			$this->getOutput()->addHTML(
227
				$pager->getNavigationBar() .
228
					$this->getActionButtons(
229
						$loglist->beginLogEventsList() .
230
							$logBody .
231
							$loglist->endLogEventsList()
232
					) .
233
					$pager->getNavigationBar()
234
			);
235
		} else {
236
			$this->getOutput()->addWikiMsg( 'logempty' );
237
		}
238
	}
239
240
	private function getActionButtons( $formcontents ) {
241
		$user = $this->getUser();
242
		$canRevDelete = $user->isAllowedAll( 'deletedhistory', 'deletelogentry' );
243
		$showTagEditUI = ChangeTags::showTagEditingUI( $user );
244
		# If the user doesn't have the ability to delete log entries nor edit tags,
245
		# don't bother showing them the button(s).
246
		if ( !$canRevDelete && !$showTagEditUI ) {
247
			return $formcontents;
248
		}
249
250
		# Show button to hide log entries and/or edit change tags
251
		$s = Html::openElement(
252
			'form',
253
			[ 'action' => wfScript(), 'id' => 'mw-log-deleterevision-submit' ]
254
		) . "\n";
255
		$s .= Html::hidden( 'action', 'historysubmit' ) . "\n";
256
		$s .= Html::hidden( 'type', 'logging' ) . "\n";
257
258
		$buttons = '';
259 View Code Duplication
		if ( $canRevDelete ) {
260
			$buttons .= Html::element(
261
				'button',
262
				[
263
					'type' => 'submit',
264
					'name' => 'revisiondelete',
265
					'value' => '1',
266
					'class' => "deleterevision-log-submit mw-log-deleterevision-button"
267
				],
268
				$this->msg( 'showhideselectedlogentries' )->text()
269
			) . "\n";
270
		}
271 View Code Duplication
		if ( $showTagEditUI ) {
272
			$buttons .= Html::element(
273
				'button',
274
				[
275
					'type' => 'submit',
276
					'name' => 'editchangetags',
277
					'value' => '1',
278
					'class' => "editchangetags-log-submit mw-log-editchangetags-button"
279
				],
280
				$this->msg( 'log-edit-tags' )->text()
281
			) . "\n";
282
		}
283
284
		$buttons .= ( new ListToggle( $this->getOutput() ) )->getHTML();
285
286
		$s .= $buttons . $formcontents . $buttons;
287
		$s .= Html::closeElement( 'form' );
288
289
		return $s;
290
	}
291
292
	/**
293
	 * Set page title and show header for this log type
294
	 * @param string $type
295
	 * @since 1.19
296
	 */
297
	protected function addHeader( $type ) {
298
		$page = new LogPage( $type );
299
		$this->getOutput()->setPageTitle( $page->getName() );
300
		$this->getOutput()->addHTML( $page->getDescription()
301
			->setContext( $this->getContext() )->parseAsBlock() );
302
	}
303
304
	protected function getGroupName() {
305
		return 'changes';
306
	}
307
}
308