// Precache various messages
if( !isset( $this->message ) ) {
$messages = array( 'revertmerge', 'protect_change', 'unblocklink', 'change-blocklink',
- 'revertmove', 'undeletelink', 'undeleteviewlink', 'revdel-restore', 'rev-delundel', 'hist', 'diff',
+ 'revertmove', 'undeletelink', 'undeleteviewlink', 'revdel-restore', 'hist', 'diff',
'pipe-separator' );
foreach( $messages as $msg ) {
$this->message[$msg] = wfMsgExt( $msg, array( 'escapenoentities' ) );
// First pass to load the log names
foreach( $validTypes as $type ) {
$text = LogPage::logName( $type );
- $typesByName[$text] = $type;
+ $typesByName[$type] = $text;
}
// Second pass to sort by name
- ksort($typesByName);
+ asort($typesByName);
// Note the query type
$queryType = count($queryTypes) == 1 ? $queryTypes[0] : '';
// Third pass generates sorted XHTML content
- foreach( $typesByName as $text => $type ) {
+ foreach( $typesByName as $type => $text ) {
$selected = ($type == $queryType);
// Restricted types
if ( isset($wgLogRestrictions[$type]) ) {
* @return string
*/
private function getShowHideLinks( $row ) {
+ global $wgUser;
+ if( $row->log_type == 'suppress' ) {
+ return ''; // No one can hide items from the oversight log
+ }
+ $canHide = $wgUser->isAllowed( 'deleterevision' );
// If event was hidden from sysops
if( !self::userCan( $row, LogPage::DELETED_RESTRICTED ) ) {
- $del = Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ),
- '(' . $this->message['rev-delundel'] . ')' );
- } else if( $row->log_type == 'suppress' ) {
- $del = ''; // No one should be hiding from the oversight log
+ $del = $this->skin->revDeleteLinkDisabled( $canHide );
} else {
$target = SpecialPage::getTitleFor( 'Log', $row->log_type );
$page = Title::makeTitle( $row->log_namespace, $row->log_title );
$query = array(
'target' => $target->getPrefixedDBkey(),
- 'type' => 'logging',
- 'ids' => $row->log_id,
+ 'type' => 'logging',
+ 'ids' => $row->log_id,
);
$del = $this->skin->revDeleteLink( $query,
- self::isDeleted( $row, LogPage::DELETED_RESTRICTED ) );
+ self::isDeleted( $row, LogPage::DELETED_RESTRICTED ), $canHide );
}
return $del;
}
* that are processed with wgMsgExt and option 'parse'
* - offset Set to overwrite offset parameter in $wgRequest
* set to '' to unset offset
+ * - wrap String: Wrap the message in html (usually something like "<div ...>$1</div>").
* @return Integer Number of total log items (not limited by $lim)
*/
public static function showLogExtract( &$out, $types=array(), $page='', $user='',
'lim' => 25,
'conds' => array(),
'showIfEmpty' => true,
- 'msgKey' => array('')
+ 'msgKey' => array(''),
+ 'wrap' => "$1"
);
# The + operator appends elements of remaining keys from the right
$conds = $param['conds'];
$showIfEmpty = $param['showIfEmpty'];
$msgKey = $param['msgKey'];
+ $wrap = $param['wrap'];
if ( !is_array( $msgKey ) )
$msgKey = array( $msgKey );
# Insert list of top 50 (or top $lim) items
$loglist->endLogEventsList();
} else {
if ( $showIfEmpty )
- $s = wfMsgExt( 'logempty', array('parse') );
+ $s = Html::rawElement( 'div', array( 'class' => 'mw-warning-logempty' ),
+ wfMsgExt( 'logempty', array( 'parseinline' ) ) );
}
if( $pager->getNumRows() > $pager->mLimit ) { # Show "Full log" link
$urlParam = array();
if ( $logBody && $msgKey[0] )
$s .= '</div>';
+ if ( $wrap!='' ) { // Wrap message in html
+ $s = str_replace( '$1', $s, $wrap );
+ }
+
+ // $out can be either an OutputPage object or a String-by-reference
if( $out instanceof OutputPage ){
$out->addHTML( $s );
} else {
$types = ($types === '') ? array() : (array)$types;
// Don't even show header for private logs; don't recognize it...
foreach ( $types as $type ) {
- if( isset( $wgLogRestrictions[$type] ) && !$wgUser->isAllowed($wgLogRestrictions[$type]) ) {
+ if( isset( $wgLogRestrictions[$type] )
+ && !$wgUser->isAllowed($wgLogRestrictions[$type])
+ ) {
$types = array_diff( $types, array( $type ) );
}
}
+ $this->types = $types;
// Don't show private logs to unprivileged users.
// Also, only show them upon specific request to avoid suprises.
$audience = $types ? 'user' : 'public';
$this->mConds[] = $hideLogs;
}
if( count($types) ) {
- $this->types = $types;
$this->mConds['log_type'] = $types;
// Set typeCGI; used in url param for paging
if( count($types) == 1 ) $this->typeCGI = $types[0];
$this->title = $title->getPrefixedText();
$ns = $title->getNamespace();
+ $db = $this->mDb;
+
# Using the (log_namespace, log_title, log_timestamp) index with a
# range scan (LIKE) on the first two parts, instead of simple equality,
# makes it unusable for sorting. Sorted retrieval using another index
# log entries for even the busiest pages, so it can be safely scanned
# in full to satisfy an impossible condition on user or similar.
if( $pattern && !$wgMiserMode ) {
- # use escapeLike to avoid expensive search patterns like 't%st%'
- $safetitle = $this->mDb->escapeLike( $title->getDBkey() );
$this->mConds['log_namespace'] = $ns;
- $this->mConds[] = "log_title LIKE '$safetitle%'";
+ $this->mConds[] = 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() );
$this->pattern = $pattern;
} else {
$this->mConds['log_namespace'] = $ns;
}
// Paranoia: avoid brute force searches (bug 17342)
if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
- $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::DELETED_ACTION) . ' = 0';
+ $this->mConds[] = $db->bitAnd('log_deleted', LogPage::DELETED_ACTION) . ' = 0';
} else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
- $this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::SUPPRESSED_ACTION) .
+ $this->mConds[] = $db->bitAnd('log_deleted', LogPage::SUPPRESSED_ACTION) .
' != ' . LogPage::SUPPRESSED_ACTION;
}
}
public function getQueryInfo() {
+ global $wgOut;
$tables = array( 'logging', 'user' );
$this->mConds[] = 'user_id = log_user';
- $groupBy = false;
+ $index = array();
+ $options = array();
# Add log_search table if there are conditions on it
if( array_key_exists('ls_field',$this->mConds) ) {
$tables[] = 'log_search';
- $index = array( 'log_search' => 'ls_field_val', 'logging' => 'PRIMARY' );
- $groupBy = 'ls_log_id';
- # Don't use the wrong logging index
+ $index['log_search'] = 'ls_field_val';
+ $index['logging'] = 'PRIMARY';
+ $options[] = 'DISTINCT';
+ # Avoid usage of the wrong index by limiting
+ # the choices of available indexes. This mainly
+ # avoids site-breaking filesorts.
} else if( $this->title || $this->pattern || $this->user ) {
- $index = array( 'logging' => array('page_time','user_time') );
- } else if( $this->types ) {
- $index = array( 'logging' => 'type_time' );
+ $index['logging'] = array( 'page_time', 'user_time' );
+ if( count($this->types) == 1 ) {
+ $index['logging'][] = 'log_user_type_time';
+ }
+ } else if( count($this->types) == 1 ) {
+ $index['logging'] = 'type_time';
} else {
- $index = array( 'logging' => 'times' );
+ $index['logging'] = 'times';
}
- $options = array( 'USE INDEX' => $index );
+ $options['USE INDEX'] = $index;
# Don't show duplicate rows when using log_search
- if( $groupBy ) $options['GROUP BY'] = $groupBy;
$info = array(
'tables' => $tables,
'fields' => array( 'log_type', 'log_action', 'log_user', 'log_namespace',
# Add ChangeTags filter query
ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'],
$info['join_conds'], $info['options'], $this->mTagFilter );
-
return $info;
}