mediawiki-extensions-AbuseF.../includes/api/ApiQueryAbuseLog.php
Daimona Eaytoy 4ab12305f1 Use string cast for Postgres compatibility
We JOIN integer and text, so Postgres would always fail on these. As
mentioned in the task description, this is only a temporary solution
(although a clean and durable one), while the long-term one is
I7460a2d63f60c2933b36f8383a8abdbba8649e12.

Bug: T42757
Change-Id: Ifddd0bca1e8eaa7c70511fb0d0588457b4fd0669
2019-03-23 12:44:02 +01:00

315 lines
9.3 KiB
PHP

<?php
/**
* Created on Mar 28, 2009
*
* AbuseFilter extension
*
* Copyright © 2008 Alex Z. mrzmanwiki AT gmail DOT com
* Based mostly on code by Bryan Tong Minh and Roan Kattouw
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*/
/**
* Query module to list abuse log entries.
*
* @ingroup API
* @ingroup Extensions
*/
class ApiQueryAbuseLog extends ApiQueryBase {
/**
* @param ApiQuery $query
* @param string $moduleName
*/
public function __construct( ApiQuery $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'afl' );
}
/**
* @inheritDoc
*/
public function execute() {
// Same check as in SpecialAbuseLog
$this->checkUserRightsAny( 'abusefilter-log' );
$user = $this->getUser();
$params = $this->extractRequestParams();
$prop = array_flip( $params['prop'] );
$fld_ids = isset( $prop['ids'] );
$fld_filter = isset( $prop['filter'] );
$fld_user = isset( $prop['user'] );
$fld_title = isset( $prop['title'] );
$fld_action = isset( $prop['action'] );
$fld_details = isset( $prop['details'] );
$fld_result = isset( $prop['result'] );
$fld_timestamp = isset( $prop['timestamp'] );
$fld_hidden = isset( $prop['hidden'] );
$fld_revid = isset( $prop['revid'] );
$isCentral = $this->getConfig()->get( 'AbuseFilterIsCentral' );
$fld_wiki = $isCentral && isset( $prop['wiki'] );
if ( $fld_details ) {
$this->checkUserRightsAny( 'abusefilter-log-detail' );
}
// Match permissions for viewing events on private filters to SpecialAbuseLog (bug 42814)
if ( $params['filter'] &&
!( AbuseFilterView::canViewPrivate() || $user->isAllowed( 'abusefilter-log-private' ) )
) {
// A specific filter parameter is set but the user isn't allowed to view all filters
if ( !is_array( $params['filter'] ) ) {
$params['filter'] = [ $params['filter'] ];
}
foreach ( $params['filter'] as $filter ) {
if ( AbuseFilter::filterHidden( $filter ) ) {
$this->dieWithError(
[ 'apierror-permissiondenied', $this->msg( 'action-abusefilter-log-private' ) ]
);
}
}
}
$result = $this->getResult();
$this->addTables( 'abuse_filter_log' );
$this->addFields( 'afl_timestamp' );
$this->addFields( 'afl_rev_id' );
$this->addFields( 'afl_deleted' );
$this->addFields( 'afl_filter' );
$this->addFieldsIf( 'afl_id', $fld_ids );
$this->addFieldsIf( 'afl_user_text', $fld_user );
$this->addFieldsIf( [ 'afl_namespace', 'afl_title' ], $fld_title );
$this->addFieldsIf( 'afl_action', $fld_action );
$this->addFieldsIf( 'afl_var_dump', $fld_details );
$this->addFieldsIf( 'afl_actions', $fld_result );
$this->addFieldsIf( 'afl_wiki', $fld_wiki );
$db = $this->getDB();
if ( $fld_filter ) {
$this->addTables( 'abuse_filter' );
$this->addFields( 'af_public_comments' );
$this->addJoinConds( [ 'abuse_filter' => [ 'LEFT JOIN',
$db->buildStringCast( 'af_id' ) . '=afl_filter' ] ] );
}
$this->addOption( 'LIMIT', $params['limit'] + 1 );
$this->addWhereIf( [ 'afl_id' => $params['logid'] ], isset( $params['logid'] ) );
$this->addWhereRange( 'afl_timestamp', $params['dir'], $params['start'], $params['end'] );
if ( isset( $params['user'] ) ) {
$u = User::newFromName( $params['user'] );
if ( $u ) {
// Username normalisation
$params['user'] = $u->getName();
$userId = $u->getId();
} elseif ( IP::isIPAddress( $params['user'] ) ) {
// It's an IP, sanitize it
$params['user'] = IP::sanitizeIP( $params['user'] );
$userId = 0;
}
if ( isset( $userId ) ) {
// Only add the WHERE for user in case it's either a valid user
// (but not necessary an existing one) or an IP.
$this->addWhere(
[
'afl_user' => $userId,
'afl_user_text' => $params['user']
]
);
}
}
$this->addWhereIf( [ 'afl_filter' => $params['filter'] ], isset( $params['filter'] ) );
$this->addWhereIf( [ 'afl_deleted' => 0 ], !SpecialAbuseLog::canSeeHidden() );
if ( isset( $params['wiki'] ) ) {
// 'wiki' won't be set if $wgAbuseFilterIsCentral = false
$this->addWhereIf( [ 'afl_wiki' => $params['wiki'] ], $isCentral );
}
$title = $params['title'];
if ( !is_null( $title ) ) {
$titleObj = Title::newFromText( $title );
if ( is_null( $titleObj ) ) {
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $title ) ] );
}
$this->addWhereFld( 'afl_namespace', $titleObj->getNamespace() );
$this->addWhereFld( 'afl_title', $titleObj->getDBkey() );
}
$res = $this->select( __METHOD__ );
$count = 0;
foreach ( $res as $row ) {
if ( ++$count > $params['limit'] ) {
// We've had enough
$ts = new MWTimestamp( $row->afl_timestamp );
$this->setContinueEnumParameter( 'start', $ts->getTimestamp( TS_ISO_8601 ) );
break;
}
$hidden = SpecialAbuseLog::isHidden( $row );
if ( $hidden === true && !SpecialAbuseLog::canSeeHidden() ) {
continue;
} elseif ( $hidden === 'implicit' ) {
$rev = Revision::newFromId( $row->afl_rev_id );
if ( !$rev->userCan( Revision::SUPPRESSED_ALL, $user ) ) {
continue;
}
}
$canSeeDetails = SpecialAbuseLog::canSeeDetails( $row->afl_filter );
$entry = [];
if ( $fld_ids ) {
$entry['id'] = intval( $row->afl_id );
$entry['filter_id'] = $canSeeDetails ? $row->afl_filter : '';
}
if ( $fld_filter ) {
$globalIndex = AbuseFilter::decodeGlobalName( $row->afl_filter );
if ( $globalIndex ) {
$entry['filter'] = AbuseFilter::getGlobalFilterDescription( $globalIndex );
} else {
$entry['filter'] = $row->af_public_comments;
}
}
if ( $fld_user ) {
$entry['user'] = $row->afl_user_text;
}
if ( $fld_wiki ) {
$entry['wiki'] = $row->afl_wiki;
}
if ( $fld_title ) {
$title = Title::makeTitle( $row->afl_namespace, $row->afl_title );
ApiQueryBase::addTitleInfo( $entry, $title );
}
if ( $fld_action ) {
$entry['action'] = $row->afl_action;
}
if ( $fld_result ) {
$entry['result'] = $row->afl_actions;
}
if ( $fld_revid && !is_null( $row->afl_rev_id ) ) {
$entry['revid'] = $canSeeDetails ? $row->afl_rev_id : '';
}
if ( $fld_timestamp ) {
$ts = new MWTimestamp( $row->afl_timestamp );
$entry['timestamp'] = $ts->getTimestamp( TS_ISO_8601 );
}
if ( $fld_details ) {
$entry['details'] = [];
if ( $canSeeDetails ) {
$vars = AbuseFilter::loadVarDump( $row->afl_var_dump );
if ( $vars instanceof AbuseFilterVariableHolder ) {
$entry['details'] = $vars->exportAllVars();
} else {
$entry['details'] = array_change_key_case( $vars, CASE_LOWER );
}
}
}
if ( $fld_hidden && $hidden ) {
$entry['hidden'] = $hidden;
}
if ( $entry ) {
$fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $entry );
if ( !$fit ) {
$ts = new MWTimestamp( $row->afl_timestamp );
$this->setContinueEnumParameter( 'start', $ts->getTimestamp( TS_ISO_8601 ) );
break;
}
}
}
$result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'item' );
}
/**
* @see ApiQueryBase::getAllowedParams()
* @return array
*/
public function getAllowedParams() {
$params = [
'logid' => [
ApiBase::PARAM_TYPE => 'integer'
],
'start' => [
ApiBase::PARAM_TYPE => 'timestamp'
],
'end' => [
ApiBase::PARAM_TYPE => 'timestamp'
],
'dir' => [
ApiBase::PARAM_TYPE => [
'newer',
'older'
],
ApiBase::PARAM_DFLT => 'older',
ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
],
'user' => null,
'title' => null,
'filter' => [
ApiBase::PARAM_TYPE => 'string',
ApiBase::PARAM_ISMULTI => true
],
'limit' => [
ApiBase::PARAM_DFLT => 10,
ApiBase::PARAM_TYPE => 'limit',
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
],
'prop' => [
ApiBase::PARAM_DFLT => 'ids|user|title|action|result|timestamp|hidden|revid',
ApiBase::PARAM_TYPE => [
'ids',
'filter',
'user',
'title',
'action',
'details',
'result',
'timestamp',
'hidden',
'revid',
],
ApiBase::PARAM_ISMULTI => true
]
];
if ( $this->getConfig()->get( 'AbuseFilterIsCentral' ) ) {
$params['wiki'] = [
ApiBase::PARAM_TYPE => 'string',
];
$params['prop'][ApiBase::PARAM_DFLT] .= '|wiki';
$params['prop'][ApiBase::PARAM_TYPE][] = 'wiki';
}
return $params;
}
/**
* @see ApiBase::getExamplesMessages()
* @return array
*/
protected function getExamplesMessages() {
return [
'action=query&list=abuselog'
=> 'apihelp-query+abuselog-example-1',
'action=query&list=abuselog&afltitle=API'
=> 'apihelp-query+abuselog-example-2',
];
}
}