Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 183 |
|
0.00% |
0 / 26 |
CRAP | |
0.00% |
0 / 1 |
LogPager | |
0.00% |
0 / 182 |
|
0.00% |
0 / 26 |
6162 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
getDefaultQuery | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
limitFilterTypes | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
getFilterParams | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
limitType | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
132 | |||
limitPerformer | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
limitTitle | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
132 | |||
limitAction | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
30 | |||
limitLogId | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getQueryInfo | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
110 | |||
hasEqualsClause | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
getIndexField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doBatchLookups | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
formatRow | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPerformer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPage | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPattern | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getYear | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getMonth | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDay | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTagFilter | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTagInvert | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
enforceActionRestrictions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
enforcePerformerRestrictions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | /** |
3 | * Contain classes to list log entries |
4 | * |
5 | * Copyright © 2004 Brooke Vibber <bvibber@wikimedia.org> |
6 | * https://www.mediawiki.org/ |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; if not, write to the Free Software Foundation, Inc., |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
21 | * http://www.gnu.org/copyleft/gpl.html |
22 | * |
23 | * @file |
24 | */ |
25 | |
26 | namespace MediaWiki\Pager; |
27 | |
28 | use DatabaseLogEntry; |
29 | use LogEventsList; |
30 | use LogFormatter; |
31 | use LogPage; |
32 | use MediaWiki\Cache\LinkBatchFactory; |
33 | use MediaWiki\MainConfigNames; |
34 | use MediaWiki\MediaWikiServices; |
35 | use MediaWiki\Page\PageReference; |
36 | use MediaWiki\Title\Title; |
37 | use MediaWiki\User\ActorNormalization; |
38 | use Wikimedia\Rdbms\IExpression; |
39 | use Wikimedia\Rdbms\LikeValue; |
40 | |
41 | /** |
42 | * @ingroup Pager |
43 | */ |
44 | class LogPager extends ReverseChronologicalPager { |
45 | /** @var array Log types */ |
46 | private $types = []; |
47 | |
48 | /** @var string Events limited to those by performer when set */ |
49 | private $performer = ''; |
50 | |
51 | /** @var string Events limited to those about this page when set */ |
52 | private $page = ''; |
53 | |
54 | /** @var bool */ |
55 | private $pattern = false; |
56 | |
57 | /** @var string */ |
58 | private $typeCGI = ''; |
59 | |
60 | /** @var string */ |
61 | private $action = ''; |
62 | |
63 | /** @var bool */ |
64 | private $performerRestrictionsEnforced = false; |
65 | |
66 | /** @var bool */ |
67 | private $actionRestrictionsEnforced = false; |
68 | |
69 | /** @var array */ |
70 | private $mConds; |
71 | |
72 | /** @var string */ |
73 | private $mTagFilter; |
74 | |
75 | /** @var bool */ |
76 | private $mTagInvert; |
77 | |
78 | /** @var LogEventsList */ |
79 | public $mLogEventsList; |
80 | |
81 | /** @var LinkBatchFactory */ |
82 | private $linkBatchFactory; |
83 | |
84 | /** @var ActorNormalization */ |
85 | private $actorNormalization; |
86 | |
87 | /** |
88 | * @param LogEventsList $list |
89 | * @param string|array $types Log types to show |
90 | * @param string $performer The user who made the log entries |
91 | * @param string|PageReference $page The page the log entries are for |
92 | * @param bool $pattern Do a prefix search rather than an exact title match |
93 | * @param array $conds Extra conditions for the query |
94 | * @param int|bool $year The year to start from. Default: false |
95 | * @param int|bool $month The month to start from. Default: false |
96 | * @param int|bool $day The day to start from. Default: false |
97 | * @param string $tagFilter Tag |
98 | * @param string $action Specific action (subtype) requested |
99 | * @param int $logId Log entry ID, to limit to a single log entry. |
100 | * @param LinkBatchFactory|null $linkBatchFactory |
101 | * @param ActorNormalization|null $actorNormalization |
102 | * @param bool $tagInvert whether tags are filtered for (false) or out (true) |
103 | */ |
104 | public function __construct( $list, $types = [], $performer = '', $page = '', |
105 | $pattern = false, $conds = [], $year = false, $month = false, $day = false, |
106 | $tagFilter = '', $action = '', $logId = 0, |
107 | LinkBatchFactory $linkBatchFactory = null, |
108 | ActorNormalization $actorNormalization = null, |
109 | $tagInvert = false |
110 | ) { |
111 | parent::__construct( $list->getContext() ); |
112 | |
113 | $services = MediaWikiServices::getInstance(); |
114 | $this->mConds = $conds; |
115 | $this->mLogEventsList = $list; |
116 | |
117 | // Class is used directly in extensions - T266480 |
118 | $this->linkBatchFactory = $linkBatchFactory ?? $services->getLinkBatchFactory(); |
119 | $this->actorNormalization = $actorNormalization ?? $services->getActorNormalization(); |
120 | |
121 | $this->limitLogId( $logId ); // set before types per T269761 |
122 | $this->limitType( $types ); // also excludes hidden types |
123 | $this->limitFilterTypes(); |
124 | $this->limitPerformer( $performer ); |
125 | $this->limitTitle( $page, $pattern ); |
126 | $this->limitAction( $action ); |
127 | $this->getDateCond( $year, $month, $day ); |
128 | $this->mTagFilter = (string)$tagFilter; |
129 | $this->mTagInvert = (bool)$tagInvert; |
130 | } |
131 | |
132 | public function getDefaultQuery() { |
133 | $query = parent::getDefaultQuery(); |
134 | $query['type'] = $this->typeCGI; // arrays won't work here |
135 | $query['user'] = $this->performer; |
136 | $query['day'] = $this->mDay; |
137 | $query['month'] = $this->mMonth; |
138 | $query['year'] = $this->mYear; |
139 | |
140 | return $query; |
141 | } |
142 | |
143 | private function limitFilterTypes() { |
144 | if ( $this->hasEqualsClause( 'log_id' ) ) { // T220834 |
145 | return; |
146 | } |
147 | $filterTypes = $this->getFilterParams(); |
148 | foreach ( $filterTypes as $type => $hide ) { |
149 | if ( $hide ) { |
150 | $this->mConds[] = 'log_type != ' . $this->mDb->addQuotes( $type ); |
151 | } |
152 | } |
153 | } |
154 | |
155 | public function getFilterParams() { |
156 | $filters = []; |
157 | if ( count( $this->types ) ) { |
158 | return $filters; |
159 | } |
160 | |
161 | // FIXME: This is broken, values from HTMLForm should be used. |
162 | $wpfilters = $this->getRequest()->getArray( "wpfilters" ); |
163 | $filterLogTypes = $this->getConfig()->get( MainConfigNames::FilterLogTypes ); |
164 | |
165 | foreach ( $filterLogTypes as $type => $default ) { |
166 | // Back-compat: Check old URL params if the new param wasn't passed |
167 | if ( $wpfilters === null ) { |
168 | $hide = $this->getRequest()->getBool( "hide_{$type}_log", $default ); |
169 | } else { |
170 | $hide = !in_array( $type, $wpfilters ); |
171 | } |
172 | |
173 | $filters[$type] = $hide; |
174 | } |
175 | |
176 | return $filters; |
177 | } |
178 | |
179 | /** |
180 | * Set the log reader to return only entries of the given type. |
181 | * Type restrictions enforced here |
182 | * |
183 | * @param string|array $types Log types ('upload', 'delete', etc); |
184 | * empty string means no restriction |
185 | */ |
186 | private function limitType( $types ) { |
187 | $restrictions = $this->getConfig()->get( MainConfigNames::LogRestrictions ); |
188 | // If $types is not an array, make it an array |
189 | $types = ( $types === '' ) ? [] : (array)$types; |
190 | // Don't even show header for private logs; don't recognize it... |
191 | $needReindex = false; |
192 | foreach ( $types as $type ) { |
193 | if ( isset( $restrictions[$type] ) |
194 | && !$this->getAuthority()->isAllowed( $restrictions[$type] ) |
195 | ) { |
196 | $needReindex = true; |
197 | $types = array_diff( $types, [ $type ] ); |
198 | } |
199 | } |
200 | if ( $needReindex ) { |
201 | // Lots of this code makes assumptions that |
202 | // the first entry in the array is $types[0]. |
203 | $types = array_values( $types ); |
204 | } |
205 | $this->types = $types; |
206 | // Don't show private logs to unprivileged users. |
207 | // Also, only show them upon specific request to avoid surprises. |
208 | // Exception: if we are showing only a single log entry based on the log id, |
209 | // we don't require that "specific request" so that the links-in-logs feature |
210 | // works. See T269761 |
211 | $audience = ( $types || $this->hasEqualsClause( 'log_id' ) ) ? 'user' : 'public'; |
212 | $hideLogs = LogEventsList::getExcludeClause( $this->mDb, $audience, $this->getAuthority() ); |
213 | if ( $hideLogs !== false ) { |
214 | $this->mConds[] = $hideLogs; |
215 | } |
216 | if ( count( $types ) ) { |
217 | $this->mConds['log_type'] = $types; |
218 | // Set typeCGI; used in url param for paging |
219 | if ( count( $types ) == 1 ) { |
220 | $this->typeCGI = $types[0]; |
221 | } |
222 | } |
223 | } |
224 | |
225 | /** |
226 | * Set the log reader to return only entries by the given user. |
227 | * |
228 | * @param string $name (In)valid user name |
229 | * @return void |
230 | */ |
231 | private function limitPerformer( $name ) { |
232 | if ( $name == '' ) { |
233 | return; |
234 | } |
235 | |
236 | $actorId = $this->actorNormalization->findActorIdByName( $name, $this->mDb ); |
237 | |
238 | if ( !$actorId ) { |
239 | // Unknown user, match nothing. |
240 | $this->mConds[] = '1 = 0'; |
241 | return; |
242 | } |
243 | |
244 | $this->mConds[ 'log_actor' ] = $actorId; |
245 | |
246 | $this->enforcePerformerRestrictions(); |
247 | |
248 | $this->performer = $name; |
249 | } |
250 | |
251 | /** |
252 | * Set the log reader to return only entries affecting the given page. |
253 | * (For the block and rights logs, this is a user page.) |
254 | * |
255 | * @param string|PageReference $page |
256 | * @param bool $pattern |
257 | * @return void |
258 | */ |
259 | private function limitTitle( $page, $pattern ) { |
260 | if ( !$page instanceof PageReference ) { |
261 | // NOTE: For some types of logs, the title may be something strange, like "User:#12345"! |
262 | $page = Title::newFromText( $page ); |
263 | if ( !$page ) { |
264 | return; |
265 | } |
266 | } |
267 | |
268 | $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter(); |
269 | $this->page = $titleFormatter->getPrefixedDBkey( $page ); |
270 | $ns = $page->getNamespace(); |
271 | $db = $this->mDb; |
272 | |
273 | $interwikiDelimiter = $this->getConfig()->get( MainConfigNames::UserrightsInterwikiDelimiter ); |
274 | |
275 | $doUserRightsLogLike = false; |
276 | if ( $this->types == [ 'rights' ] ) { |
277 | $parts = explode( $interwikiDelimiter, $page->getDBkey() ); |
278 | if ( count( $parts ) == 2 ) { |
279 | [ $name, $database ] = array_map( 'trim', $parts ); |
280 | if ( str_contains( $database, '*' ) ) { |
281 | $doUserRightsLogLike = true; |
282 | } |
283 | } |
284 | } |
285 | |
286 | /** |
287 | * Using the (log_namespace, log_title, log_timestamp) index with a |
288 | * range scan (LIKE) on the first two parts, instead of simple equality, |
289 | * makes it unusable for sorting. Sorted retrieval using another index |
290 | * would be possible, but then we might have to scan arbitrarily many |
291 | * nodes of that index. Therefore, we need to avoid this if $wgMiserMode |
292 | * is on. |
293 | * |
294 | * This is not a problem with simple title matches, because then we can |
295 | * use the log_page_time index. That should have no more than a few hundred |
296 | * log entries for even the busiest pages, so it can be safely scanned |
297 | * in full to satisfy an impossible condition on user or similar. |
298 | */ |
299 | $this->mConds['log_namespace'] = $ns; |
300 | if ( $doUserRightsLogLike ) { |
301 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable $name is set when reached here |
302 | $params = [ $name . $interwikiDelimiter ]; |
303 | // @phan-suppress-next-next-line PhanPossiblyUndeclaredVariable $database is set when reached here |
304 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal $database is set when reached here |
305 | $databaseParts = explode( '*', $database ); |
306 | $databasePartCount = count( $databaseParts ); |
307 | foreach ( $databaseParts as $i => $databasepart ) { |
308 | $params[] = $databasepart; |
309 | if ( $i < $databasePartCount - 1 ) { |
310 | $params[] = $db->anyString(); |
311 | } |
312 | } |
313 | $this->mConds[] = $db->expr( 'log_title', IExpression::LIKE, new LikeValue( ...$params ) ); |
314 | } elseif ( $pattern && !$this->getConfig()->get( MainConfigNames::MiserMode ) ) { |
315 | $this->mConds[] = $db->expr( |
316 | 'log_title', |
317 | IExpression::LIKE, |
318 | new LikeValue( $page->getDBkey(), $db->anyString() ) |
319 | ); |
320 | $this->pattern = $pattern; |
321 | } else { |
322 | $this->mConds['log_title'] = $page->getDBkey(); |
323 | } |
324 | $this->enforceActionRestrictions(); |
325 | } |
326 | |
327 | /** |
328 | * Set the log_action field to a specified value (or values) |
329 | * |
330 | * @param string $action |
331 | */ |
332 | private function limitAction( $action ) { |
333 | // Allow to filter the log by actions |
334 | $type = $this->typeCGI; |
335 | if ( $type === '' ) { |
336 | // nothing to do |
337 | return; |
338 | } |
339 | $actions = $this->getConfig()->get( MainConfigNames::ActionFilteredLogs ); |
340 | if ( isset( $actions[$type] ) ) { |
341 | // log type can be filtered by actions |
342 | if ( $action !== '' && isset( $actions[$type][$action] ) ) { |
343 | // add condition to query |
344 | $this->mConds['log_action'] = $actions[$type][$action]; |
345 | $this->action = $action; |
346 | } |
347 | } |
348 | } |
349 | |
350 | /** |
351 | * Limit to the (single) specified log ID. |
352 | * @param int $logId The log entry ID. |
353 | */ |
354 | protected function limitLogId( $logId ) { |
355 | if ( !$logId ) { |
356 | return; |
357 | } |
358 | $this->mConds['log_id'] = $logId; |
359 | } |
360 | |
361 | /** |
362 | * Constructs the most part of the query. Extra conditions are sprinkled in |
363 | * all over this class. |
364 | * @return array |
365 | */ |
366 | public function getQueryInfo() { |
367 | $queryBuilder = DatabaseLogEntry::newSelectQueryBuilder( $this->mDb ) |
368 | ->where( $this->mConds ); |
369 | |
370 | # Add log_search table if there are conditions on it. |
371 | # This filters the results to only include log rows that have |
372 | # log_search records with the specified ls_field and ls_value values. |
373 | if ( array_key_exists( 'ls_field', $this->mConds ) ) { |
374 | $queryBuilder->join( 'log_search', null, 'ls_log_id=log_id' ); |
375 | $queryBuilder->ignoreIndex( [ 'log_search' => 'ls_log_id' ] ); |
376 | $queryBuilder->useIndex( [ 'logging' => 'PRIMARY' ] ); |
377 | if ( !$this->hasEqualsClause( 'ls_field' ) |
378 | || !$this->hasEqualsClause( 'ls_value' ) |
379 | ) { |
380 | # Since (ls_field,ls_value,ls_logid) is unique, if the condition is |
381 | # to match a specific (ls_field,ls_value) tuple, then there will be |
382 | # no duplicate log rows. Otherwise, we need to remove the duplicates. |
383 | $queryBuilder->distinct(); |
384 | } |
385 | } elseif ( array_key_exists( 'log_actor', $this->mConds ) ) { |
386 | // Optimizer doesn't pick the right index when a user has lots of log actions (T303089) |
387 | $index = 'log_actor_time'; |
388 | foreach ( $this->getFilterParams() as $hide ) { |
389 | if ( !$hide ) { |
390 | $index = 'log_actor_type_time'; |
391 | break; |
392 | } |
393 | } |
394 | $queryBuilder->useIndex( [ 'logging' => $index ] ); |
395 | } |
396 | |
397 | // T221458: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before |
398 | // `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`. |
399 | // Tell it not to reorder the query. But not when tag filtering or log_search was used, as it |
400 | // seems as likely to be harmed as helped in that case. |
401 | if ( $this->mTagFilter === '' && !array_key_exists( 'ls_field', $this->mConds ) ) { |
402 | $queryBuilder->option( 'STRAIGHT_JOIN' ); |
403 | } |
404 | |
405 | $maxExecTime = $this->getConfig()->get( MainConfigNames::MaxExecutionTimeForExpensiveQueries ); |
406 | if ( $maxExecTime ) { |
407 | $queryBuilder->setMaxExecutionTime( $maxExecTime ); |
408 | } |
409 | |
410 | # Add ChangeTags filter query |
411 | MediaWikiServices::getInstance()->getChangeTagsStore()->modifyDisplayQueryBuilder( |
412 | $queryBuilder, |
413 | 'logging', |
414 | $this->mTagFilter, |
415 | $this->mTagInvert |
416 | ); |
417 | |
418 | return $queryBuilder->getQueryInfo(); |
419 | } |
420 | |
421 | /** |
422 | * Checks if $this->mConds has $field matched to a *single* value |
423 | * @param string $field |
424 | * @return bool |
425 | */ |
426 | protected function hasEqualsClause( $field ) { |
427 | return ( |
428 | array_key_exists( $field, $this->mConds ) && |
429 | ( !is_array( $this->mConds[$field] ) || count( $this->mConds[$field] ) == 1 ) |
430 | ); |
431 | } |
432 | |
433 | public function getIndexField() { |
434 | return [ [ 'log_timestamp', 'log_id' ] ]; |
435 | } |
436 | |
437 | protected function doBatchLookups() { |
438 | $lb = $this->linkBatchFactory->newLinkBatch(); |
439 | foreach ( $this->mResult as $row ) { |
440 | $lb->add( $row->log_namespace, $row->log_title ); |
441 | $lb->add( NS_USER, $row->log_user_text ); |
442 | $lb->add( NS_USER_TALK, $row->log_user_text ); |
443 | $formatter = LogFormatter::newFromRow( $row ); |
444 | foreach ( $formatter->getPreloadTitles() as $title ) { |
445 | $lb->addObj( $title ); |
446 | } |
447 | } |
448 | $lb->execute(); |
449 | } |
450 | |
451 | public function formatRow( $row ) { |
452 | return $this->mLogEventsList->logLine( $row ); |
453 | } |
454 | |
455 | public function getType() { |
456 | return $this->types; |
457 | } |
458 | |
459 | /** |
460 | * Guaranteed to either return a valid title string or a Zero-Length String |
461 | * |
462 | * @return string |
463 | */ |
464 | public function getPerformer() { |
465 | return $this->performer; |
466 | } |
467 | |
468 | /** |
469 | * @return string |
470 | */ |
471 | public function getPage() { |
472 | return $this->page; |
473 | } |
474 | |
475 | /** |
476 | * @return bool |
477 | */ |
478 | public function getPattern() { |
479 | return $this->pattern; |
480 | } |
481 | |
482 | public function getYear() { |
483 | return $this->mYear; |
484 | } |
485 | |
486 | public function getMonth() { |
487 | return $this->mMonth; |
488 | } |
489 | |
490 | public function getDay() { |
491 | return $this->mDay; |
492 | } |
493 | |
494 | public function getTagFilter() { |
495 | return $this->mTagFilter; |
496 | } |
497 | |
498 | public function getTagInvert() { |
499 | return $this->mTagInvert; |
500 | } |
501 | |
502 | public function getAction() { |
503 | return $this->action; |
504 | } |
505 | |
506 | /** |
507 | * Paranoia: avoid brute force searches (T19342) |
508 | */ |
509 | private function enforceActionRestrictions() { |
510 | if ( $this->actionRestrictionsEnforced ) { |
511 | return; |
512 | } |
513 | $this->actionRestrictionsEnforced = true; |
514 | if ( !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) { |
515 | $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_ACTION ) . ' = 0'; |
516 | } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { |
517 | $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_ACTION ) . |
518 | ' != ' . LogPage::SUPPRESSED_USER; |
519 | } |
520 | } |
521 | |
522 | /** |
523 | * Paranoia: avoid brute force searches (T19342) |
524 | */ |
525 | private function enforcePerformerRestrictions() { |
526 | // Same as enforceActionRestrictions(), except for _USER instead of _ACTION bits. |
527 | if ( $this->performerRestrictionsEnforced ) { |
528 | return; |
529 | } |
530 | $this->performerRestrictionsEnforced = true; |
531 | if ( !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) { |
532 | $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0'; |
533 | } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { |
534 | $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_USER ) . |
535 | ' != ' . LogPage::SUPPRESSED_ACTION; |
536 | } |
537 | } |
538 | } |
539 | |
540 | /** @deprecated class alias since 1.41 */ |
541 | class_alias( LogPager::class, 'LogPager' ); |