39
39
// Precache various messages
40
40
if( !isset( $this->message ) ) {
41
41
$messages = array( 'revertmerge', 'protect_change', 'unblocklink', 'change-blocklink',
42
'revertmove', 'undeletelink', 'revdel-restore', 'rev-delundel', 'hist', 'pipe-separator' );
42
'revertmove', 'undeletelink', 'revdel-restore', 'rev-delundel', 'hist', 'diff',
43
44
foreach( $messages as $msg ) {
44
$this->message[$msg] = wfMsgExt( $msg, array( 'escape' ) );
45
$this->message[$msg] = wfMsgExt( $msg, array( 'escapenoentities' ) );
65
66
* @param $pattern String
66
67
* @param $year Integer: year
67
68
* @param $month Integer: month
68
* @param $filter Boolean
69
* @param $filter: array
70
* @param $tagFilter: array?
70
72
public function showOptions( $type = '', $user = '', $page = '', $pattern = '', $year = '',
71
$month = '', $filter = null )
73
$month = '', $filter = null, $tagFilter='' )
73
75
global $wgScript, $wgMiserMode;
74
76
$action = htmlspecialchars( $wgScript );
75
77
$title = SpecialPage::getTitleFor( 'Log' );
76
78
$special = htmlspecialchars( $title->getPrefixedDBkey() );
80
$tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter );
78
82
$this->out->addHTML( "<form action=\"$action\" method=\"get\"><fieldset>" .
79
83
Xml::element( 'legend', array(), wfMsg( 'log' ) ) .
80
84
Xml::hidden( 'title', $special ) . "\n" .
82
86
$this->getUserInput( $user ) . "\n" .
83
87
$this->getTitleInput( $page ) . "\n" .
84
88
( !$wgMiserMode ? ($this->getTitlePattern( $pattern )."\n") : "" ) .
85
"<p>" . $this->getDateMenu( $year, $month ) . "\n" .
86
( $filter ? "</p><p>".$this->getFilterLinks( $type, $filter )."\n" : "" ) .
89
"<p>" . Xml::dateMenu( $year, $month ) . "\n" .
90
( $tagSelector ? Xml::tags( 'p', null, implode( ' ', $tagSelector ) ) :'' ). "\n" .
91
( $filter ? "</p><p>".$this->getFilterLinks( $type, $filter )."\n" : "" ) . "\n" .
87
92
Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "</p>\n" .
88
93
"</fieldset></form>"
92
97
private function getFilterLinks( $logType, $filter ) {
98
global $wgTitle, $wgLang;
95
100
$messages = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
96
101
// Option value -> message mapping
103
$hiddens = ''; // keep track for "go" button
98
104
foreach( $filter as $type => $val ) {
99
105
$hideVal = 1 - intval($val);
100
106
$link = $this->skin->makeKnownLinkObj( $wgTitle, $messages[$hideVal],
101
107
wfArrayToCGI( array( "hide_{$type}_log" => $hideVal ), $this->getDefaultQuery() )
103
109
$links[$type] = wfMsgHtml( "log-show-hide-{$type}", $link );
110
$hiddens .= Xml::hidden( "hide_{$type}_log", $val ) . "\n";
106
return implode( ' | ', $links );
113
return '<small>'.$wgLang->pipeList( $links ) . '</small>' . $hiddens;
109
116
private function getDefaultQuery() {
163
170
* @return String: Formatted HTML
165
172
private function getUserInput( $user ) {
166
return Xml::inputLabel( wfMsg( 'specialloguserlabel' ), 'user', 'user', 15, $user );
173
return Xml::inputLabel( wfMsg( 'specialloguserlabel' ), 'user', 'mw-log-user', 15, $user );
171
178
* @return String: Formatted HTML
173
180
private function getTitleInput( $title ) {
174
return Xml::inputLabel( wfMsg( 'speciallogtitlelabel' ), 'page', 'page', 20, $title );
178
* @param $year Integer
179
* @param $month Integer
180
* @return string Formatted HTML
182
private function getDateMenu( $year, $month ) {
183
# Offset overrides year/month selection
184
if( $month && $month !== -1 ) {
185
$encMonth = intval( $month );
190
$encYear = intval( $year );
191
} else if( $encMonth ) {
192
$thisMonth = intval( gmdate( 'n' ) );
193
$thisYear = intval( gmdate( 'Y' ) );
194
if( intval($encMonth) > $thisMonth ) {
197
$encYear = $thisYear;
201
return Xml::label( wfMsg( 'year' ), 'year' ) . ' '.
202
Xml::input( 'year', 4, $encYear, array('id' => 'year', 'maxlength' => 4) ) .
204
Xml::label( wfMsg( 'month' ), 'month' ) . ' '.
205
Xml::monthSelector( $encMonth, -1 );
181
return Xml::inputLabel( wfMsg( 'speciallogtitlelabel' ), 'page', 'mw-log-page', 20, $title );
230
206
global $wgLang, $wgUser, $wgContLang;
232
208
$title = Title::makeTitle( $row->log_namespace, $row->log_title );
209
$classes = array( "mw-logline-{$row->log_type}" );
233
210
$time = $wgLang->timeanddate( wfTimestamp(TS_MW, $row->log_timestamp), true );
235
212
if( self::isDeleted($row,LogPage::DELETED_USER) ) {
277
254
array( 'action' => 'unblock', 'ip' => $row->log_title ),
279
. ' ' . $this->message['pipe-separator'] . ' ' .
256
. $this->message['pipe-separator'] .
280
257
$this->skin->link( SpecialPage::getTitleFor( 'Blockip', $row->log_title ),
281
258
$this->message['change-blocklink'],
282
259
array(), array(), 'known' ) .
290
267
array( 'action' => 'history', 'offset' => $row->log_timestamp ) );
291
268
if( $wgUser->isAllowed( 'protect' ) ) {
292
$revert .= ' ' . $this->message['pipe-separator'] . ' ' .
269
$revert .= $this->message['pipe-separator'] .
293
270
$this->skin->link( $title,
294
271
$this->message['protect_change'],
315
292
foreach( $Ids as $n => $id ) {
316
293
$revParams .= '&' . urlencode($key) . '[]=' . urlencode($id);
318
$revert = '(' . $this->skin->makeKnownLinkObj( $revdel, $this->message['revdel-restore'],
319
'target=' . $title->getPrefixedUrl() . $revParams ) . ')';
296
// Diff link for single rev deletions
297
if( $key === 'oldid' && count($Ids) == 1 ) {
298
$token = urlencode( $wgUser->editToken( intval($Ids[0]) ) );
299
$revert[] = $this->skin->makeKnownLinkObj( $title, $this->message['diff'],
300
'diff='.intval($Ids[0])."&unhide=1&token=$token" );
302
// View/modify link...
303
$revert[] = $this->skin->makeKnownLinkObj( $revdel, $this->message['revdel-restore'],
304
'target=' . $title->getPrefixedUrl() . $revParams );
305
$revert = '(' . implode(' | ',$revert) . ')';
321
307
// Hidden log items, give review link
322
308
} else if( self::typeAction($row,array('delete','suppress'),'event','deleterevision') ) {
357
343
$this->skin, $paramArray, true );
347
list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow( $row->ts_tags, 'logevent' );
348
$classes = array_merge( $classes, $newClasses );
360
350
if( $revert != '' ) {
361
351
$revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
364
return Xml::tags( 'li', array( "class" => "mw-logline-$row->log_type" ),
365
$del . $time . ' ' . $userLink . ' ' . $action . ' ' . $comment . ' ' . $revert );
354
return Xml::tags( 'li', array( "class" => implode( ' ', $classes ) ),
355
$del . $time . ' ' . $userLink . ' ' . $action . ' ' . $comment . ' ' . $revert . " $tagDisplay" ) . "\n";
373
363
$revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
374
364
// If event was hidden from sysops
375
365
if( !self::userCan( $row, LogPage::DELETED_RESTRICTED ) ) {
376
$del = $this->message['rev-delundel'];
366
$del = Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ), '('.$this->message['rev-delundel'].')' );
377
367
} else if( $row->log_type == 'suppress' ) {
378
368
// No one should be hiding from the oversight log
379
$del = $this->message['rev-delundel'];
369
$del = Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ), '('.$this->message['rev-delundel'].')' );
381
371
$target = SpecialPage::getTitleFor( 'Log', $row->log_type );
382
$del = $this->skin->makeKnownLinkObj( $revdel, $this->message['rev-delundel'],
383
'target=' . $target->getPrefixedUrl() . '&logid='.$row->log_id );
384
// Bolden oversighted content
385
if( self::isDeleted( $row, LogPage::DELETED_RESTRICTED ) )
386
$del = "<strong>$del</strong>";
372
$query = array( 'target' => $target->getPrefixedDBkey(),
373
'logid[]' => $row->log_id
375
$del = $this->skin->revDeleteLink( $query, self::isDeleted( $row, LogPage::DELETED_RESTRICTED ) );
388
return "<tt>(<small>$del</small>)</tt>";
469
458
* SQL clause to skip forbidden log types for this user
470
459
* @param $db Database
460
* @param $audience string, public/user
471
461
* @return mixed (string or false)
473
public static function getExcludeClause( $db ) {
463
public static function getExcludeClause( $db, $audience = 'public' ) {
474
464
global $wgLogRestrictions, $wgUser;
475
465
// Reset the array, clears extra "where" clauses when $par is used
476
466
$hiddenLogs = array();
477
467
// Don't show private logs to unprivileged users
478
468
foreach( $wgLogRestrictions as $logType => $right ) {
479
if( !$wgUser->isAllowed($right) ) {
469
if( $audience == 'public' || !$wgUser->isAllowed($right) ) {
480
470
$safeType = $db->strencode( $logType );
481
471
$hiddenLogs[] = $safeType;
509
499
* @param $month Integer
511
501
public function __construct( $list, $type = '', $user = '', $title = '', $pattern = '',
512
$conds = array(), $year = false, $month = false )
502
$conds = array(), $year = false, $month = false, $tagFilter = '' )
514
504
parent::__construct();
515
505
$this->mConds = $conds;
517
507
$this->mLogEventsList = $list;
519
$this->limitType( $type );
509
$this->limitType( $type ); // also excludes hidden types
520
510
$this->limitUser( $user );
521
511
$this->limitTitle( $title, $pattern );
522
512
$this->getDateCond( $year, $month );
513
$this->mTagFilter = $tagFilter;
525
516
public function getDefaultQuery() {
560
551
if( isset($wgLogRestrictions[$type]) && !$wgUser->isAllowed($wgLogRestrictions[$type]) ) {
563
// Don't show private logs to unpriviledged users
564
$hideLogs = LogEventsList::getExcludeClause( $this->mDb );
554
// Don't show private logs to unpriviledged users.
555
// Also, only show them upon specific request to avoid suprises.
556
$audience = $type ? 'user' : 'public';
557
$hideLogs = LogEventsList::getExcludeClause( $this->mDb, $audience );
565
558
if( $hideLogs !== false ) {
566
559
$this->mConds[] = $hideLogs;
563
$this->mConds['log_type'] = $type;
572
$this->mConds['log_type'] = $type;
591
583
but for now it won't pass anywhere behind the optimizer */
592
584
$this->mConds[] = "NULL";
594
587
$this->mConds['log_user'] = $userid;
588
// Paranoia: avoid brute force searches (bug 17342)
589
if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
590
$this->mConds[] = 'log_deleted & ' . LogPage::DELETED_USER . ' = 0';
595
592
$this->user = $usertitle->getText();
603
600
* @param $pattern String
605
602
private function limitTitle( $page, $pattern ) {
603
global $wgMiserMode, $wgUser;
608
605
$title = Title::newFromText( $page );
609
606
if( strlen($page) == 0 || !$title instanceof Title )
632
629
$this->mConds['log_namespace'] = $ns;
633
630
$this->mConds['log_title'] = $title->getDBkey();
632
// Paranoia: avoid brute force searches (bug 17342)
633
if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
634
$this->mConds[] = 'log_deleted & ' . LogPage::DELETED_ACTION . ' = 0';
637
638
public function getQueryInfo() {
645
646
$index = array( 'USE INDEX' => array( 'logging' => 'times' ) );
648
649
'tables' => array( 'logging', 'user' ),
649
650
'fields' => array( 'log_type', 'log_action', 'log_user', 'log_namespace', 'log_title', 'log_params',
650
651
'log_comment', 'log_id', 'log_deleted', 'log_timestamp', 'user_name', 'user_editcount' ),
651
652
'conds' => $this->mConds,
654
'join_conds' => array( 'user' => array( 'INNER JOIN', 'user_id=log_user' ) ),
657
ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'],
658
$info['join_conds'], $info['options'], $this->mTagFilter );
656
663
function getIndexField() {
722
733
$pattern = $request->getBool( 'pattern' );
723
734
$year = $request->getIntOrNull( 'year' );
724
735
$month = $request->getIntOrNull( 'month' );
736
$tagFilter = $request->getVal( 'tagfilter' );
725
737
# Don't let the user get stuck with a certain date
726
738
$skip = $request->getText( 'offset' ) || $request->getText( 'dir' ) == 'prev';
731
743
# Use new list class to output results
732
744
$loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
733
$this->pager = new LogPager( $loglist, $type, $user, $title, $pattern, $year, $month );
745
$this->pager = new LogPager( $loglist, $type, $user, $title, $pattern, $year, $month, $tagFilter );