// Order is significant here
$this->addTables( array( 'logging', 'user', 'page' ) );
- $this->addOption( 'STRAIGHT_JOIN' );
$this->addJoinConds( array(
'user' => array( 'LEFT JOIN',
'user_id=log_user' ),
'page' => array( 'LEFT JOIN',
array( 'log_namespace=page_namespace',
'log_title=page_title' ) ) ) );
- $index = array( 'logging' => 'times' ); // default, may change
$this->addFields( array(
'log_type',
}
if ( !is_null( $params['action'] ) ) {
- list( $type, $action ) = explode( '/', $params['action'] );
+ // Do validation of action param, list of allowed actions can contains wildcards
+ // Allow the param, when the actions is in the list or a wildcard version is listed.
+ $logAction = $params['action'];
+ if ( strpos( $logAction, '/' ) === false ) {
+ // all items in the list have a slash
+ $valid = false;
+ } else {
+ $logActions = array_flip( $this->getAllowedLogActions() );
+ list( $type, $action ) = explode( '/', $logAction, 2 );
+ $valid = isset( $logActions[$logAction] ) || isset( $logActions[$type . '/*'] );
+ }
+
+ if ( !$valid ) {
+ $valueName = $this->encodeParamName( 'action' );
+ $this->dieUsage(
+ "Unrecognized value for parameter '$valueName': {$logAction}",
+ "unknown_$valueName"
+ );
+ }
+
$this->addWhereFld( 'log_type', $type );
$this->addWhereFld( 'log_action', $action );
} elseif ( !is_null( $params['type'] ) ) {
$this->addWhereFld( 'log_type', $params['type'] );
- $index['logging'] = 'type_time';
}
$this->addTimestampWhereRange(
$user = $params['user'];
if ( !is_null( $user ) ) {
$userid = User::idFromName( $user );
- if ( !$userid ) {
- $this->dieUsage( "User name $user not found", 'param_user' );
+ if ( $userid ) {
+ $this->addWhereFld( 'log_user', $userid );
+ } else {
+ $this->addWhereFld( 'log_user_text', IP::sanitizeIP( $user ) );
}
- $this->addWhereFld( 'log_user', $userid );
- $index['logging'] = 'user_time';
}
$title = $params['title'];
}
$this->addWhereFld( 'log_namespace', $titleObj->getNamespace() );
$this->addWhereFld( 'log_title', $titleObj->getDBkey() );
-
- // Use the title index in preference to the user index if there is a conflict
- $index['logging'] = is_null( $user ) ? 'page_time' : array( 'page_time', 'user_time' );
}
$prefix = $params['prefix'];
$this->addWhere( 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() ) );
}
- $this->addOption( 'USE INDEX', $index );
-
// Paranoia: avoid brute force searches (bug 17342)
- if ( !is_null( $title ) ) {
- $this->addWhere( $db->bitAnd( 'log_deleted', LogPage::DELETED_ACTION ) . ' = 0' );
- }
- if ( !is_null( $user ) ) {
- $this->addWhere( $db->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0' );
+ if ( !is_null( $title ) || !is_null( $user ) ) {
+ if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
+ $titleBits = LogPage::DELETED_ACTION;
+ $userBits = LogPage::DELETED_USER;
+ } elseif ( !$this->getUser()->isAllowed( 'suppressrevision' ) ) {
+ $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
+ $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED;
+ } else {
+ $titleBits = 0;
+ $userBits = 0;
+ }
+ if ( !is_null( $title ) && $titleBits ) {
+ $this->addWhere( $db->bitAnd( 'log_deleted', $titleBits ) . " != $titleBits" );
+ }
+ if ( !is_null( $user ) && $userBits ) {
+ $this->addWhere( $db->bitAnd( 'log_deleted', $userBits ) . " != $userBits" );
+ }
}
$count = 0;
private function extractRowInfo( $row ) {
$logEntry = DatabaseLogEntry::newFromRow( $row );
$vals = array();
+ $anyHidden = false;
+ $user = $this->getUser();
if ( $this->fld_ids ) {
$vals['logid'] = intval( $row->log_id );
- $vals['pageid'] = intval( $row->page_id );
}
if ( $this->fld_title || $this->fld_parsedcomment ) {
$title = Title::makeTitle( $row->log_namespace, $row->log_title );
}
- if ( $this->fld_title ) {
+ if ( $this->fld_title || $this->fld_ids || $this->fld_details && $row->log_params !== '' ) {
if ( LogEventsList::isDeleted( $row, LogPage::DELETED_ACTION ) ) {
$vals['actionhidden'] = '';
- } else {
- ApiQueryBase::addTitleInfo( $vals, $title );
+ $anyHidden = true;
+ }
+ if ( LogEventsList::userCan( $row, LogPage::DELETED_ACTION, $user ) ) {
+ if ( $this->fld_title ) {
+ ApiQueryBase::addTitleInfo( $vals, $title );
+ }
+ if ( $this->fld_ids ) {
+ $vals['pageid'] = intval( $row->page_id );
+ }
+ if ( $this->fld_details && $row->log_params !== '' ) {
+ self::addLogParams(
+ $this->getResult(),
+ $vals,
+ $logEntry->getParameters(),
+ $logEntry->getType(),
+ $logEntry->getSubtype(),
+ $logEntry->getTimestamp(),
+ $logEntry->isLegacy()
+ );
+ }
}
}
$vals['action'] = $row->log_action;
}
- if ( $this->fld_details && $row->log_params !== '' ) {
- if ( LogEventsList::isDeleted( $row, LogPage::DELETED_ACTION ) ) {
- $vals['actionhidden'] = '';
- } else {
- self::addLogParams(
- $this->getResult(),
- $vals,
- $logEntry->getParameters(),
- $logEntry->getType(),
- $logEntry->getSubtype(),
- $logEntry->getTimestamp(),
- $logEntry->isLegacy()
- );
- }
- }
-
if ( $this->fld_user || $this->fld_userid ) {
if ( LogEventsList::isDeleted( $row, LogPage::DELETED_USER ) ) {
$vals['userhidden'] = '';
- } else {
+ $anyHidden = true;
+ }
+ if ( LogEventsList::userCan( $row, LogPage::DELETED_USER, $user ) ) {
if ( $this->fld_user ) {
$vals['user'] = $row->user_name === null ? $row->log_user_text : $row->user_name;
}
if ( ( $this->fld_comment || $this->fld_parsedcomment ) && isset( $row->log_comment ) ) {
if ( LogEventsList::isDeleted( $row, LogPage::DELETED_COMMENT ) ) {
$vals['commenthidden'] = '';
- } else {
+ $anyHidden = true;
+ }
+ if ( LogEventsList::userCan( $row, LogPage::DELETED_COMMENT, $user ) ) {
if ( $this->fld_comment ) {
$vals['comment'] = $row->log_comment;
}
}
}
+ if ( $anyHidden && LogEventsList::isDeleted( $row, LogPage::DELETED_RESTRICTED ) ) {
+ $vals['suppressed'] = '';
+ }
+
return $vals;
}
+ private function getAllowedLogActions() {
+ global $wgLogActions, $wgLogActionsHandlers;
+
+ return array_keys( array_merge( $wgLogActions, $wgLogActionsHandlers ) );
+ }
+
public function getCacheMode( $params ) {
+ if ( $this->userCanSeeRevDel() ) {
+ return 'private';
+ }
if ( !is_null( $params['prop'] ) && in_array( 'parsedcomment', $params['prop'] ) ) {
// formatComment() calls wfMessage() among other things
return 'anon-public-user-private';
}
}
- public function getAllowedParams() {
- global $wgLogTypes, $wgLogActions, $wgLogActionsHandlers;
+ public function getAllowedParams( $flags = 0 ) {
+ global $wgLogTypes;
return array(
'prop' => array(
ApiBase::PARAM_TYPE => $wgLogTypes
),
'action' => array(
- ApiBase::PARAM_TYPE => array_keys( array_merge( $wgLogActions, $wgLogActionsHandlers ) )
+ // validation on request is done in execute()
+ ApiBase::PARAM_TYPE => ( $flags & ApiBase::GET_VALUES_FOR_HELP )
+ ? $this->getAllowedLogActions()
+ : null
),
'start' => array(
ApiBase::PARAM_TYPE => 'timestamp'
' tags - Lists tags for the event',
),
'type' => 'Filter log entries to only this type',
- 'action' => "Filter log actions to only this type. Overrides {$p}type",
+ 'action' => array(
+ "Filter log actions to only this action. Overrides {$p}type",
+ "Wildcard actions like 'action/*' allows to specify any string for the asterisk"
+ ),
'start' => 'The timestamp to start enumerating from',
'end' => 'The timestamp to end enumerating',
'dir' => $this->getDirectionDescription( $p ),
}
public function getDescription() {
- return 'Get events from logs';
+ return 'Get events from logs.';
}
public function getPossibleErrors() {