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'] && !( AbuseFilter::canViewPrivate( $user ) || $this->getPermissionManager()->userHasRight( $user, '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 ) { list( $filterID, $global ) = AbuseFilter::splitGlobalName( $filter ); if ( AbuseFilter::filterHidden( $filterID, $global ) ) { $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 ); if ( $fld_filter ) { $this->addTables( 'abuse_filter' ); $this->addFields( 'af_public_comments' ); $this->addJoinConds( [ 'abuse_filter' => [ 'LEFT JOIN', '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 ( IPUtils::isIPAddress( $params['user'] ) ) { // It's an IP, sanitize it $params['user'] = IPUtils::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'] ] ); } } if ( isset( $params['filter'] ) && $params['filter'] !== [] ) { $this->addWhere( [ 'afl_filter' => $params['filter'] ] ); } $this->addWhereIf( [ 'afl_deleted' => 0 ], !SpecialAbuseLog::canSeeHidden( $user ) ); if ( isset( $params['wiki'] ) ) { // 'wiki' won't be set if $wgAbuseFilterIsCentral = false $this->addWhereIf( [ 'afl_wiki' => $params['wiki'] ], $isCentral ); } $title = $params['title']; if ( $title !== null ) { $titleObj = Title::newFromText( $title ); if ( $titleObj === null ) { $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( $user ) ) { continue; } if ( $hidden === 'implicit' ) { $revRec = MediaWikiServices::getInstance() ->getRevisionLookup() ->getRevisionById( (int)$row->afl_rev_id ); if ( !AbuseFilter::userCanViewRev( $revRec, $user ) ) { continue; } } list( $filterID, $global ) = AbuseFilter::splitGlobalName( $row->afl_filter ); $canSeeDetails = SpecialAbuseLog::canSeeDetails( $user, $filterID, $global ); $entry = []; if ( $fld_ids ) { $entry['id'] = intval( $row->afl_id ); $entry['filter_id'] = $canSeeDetails ? $row->afl_filter : ''; } if ( $fld_filter ) { if ( $global ) { $entry['filter'] = AbuseFilter::getGlobalFilterDescription( $filterID ); } 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 && $row->afl_rev_id !== null ) { $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, ApiBase::PARAM_HELP_MSG => [ 'apihelp-query+abuselog-param-filter', AbuseFilter::GLOBAL_FILTER_PREFIX ] ], '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', ]; } }