From 61233fc84724833dc487ecc55e27c1b39459befc Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Sun, 10 Aug 2014 11:25:29 +0100 Subject: [PATCH] API: Move parameter formatting into LogFormatter This allows for extensions to format their log entry parameters, and keeps the code for formatting API log entry parameters in the same place as for other formatting. This also takes the opportunity to rearrange the output format slightly to avoid conflicts like what's happening in T73020. Bug: T35235 Bug: T73020 Bug: T91466 Change-Id: I6846ce09322eb404c506b5a51780a44ce9279fe2 --- RELEASE-NOTES-1.25 | 18 +++ autoload.php | 1 + includes/DefaultSettings.php | 8 +- includes/api/ApiQueryLogEvents.php | 153 ++---------------- includes/api/ApiQueryRecentChanges.php | 11 +- includes/api/ApiQueryWatchlist.php | 11 +- includes/logging/BlockLogFormatter.php | 43 +++++ includes/logging/DeleteLogFormatter.php | 63 ++++++++ includes/logging/LogFormatter.php | 118 +++++++++++++- includes/logging/MergeLogFormatter.php | 20 +++ includes/logging/MoveLogFormatter.php | 21 +++ includes/logging/PatrolLogFormatter.php | 20 +++ includes/logging/RightsLogFormatter.php | 31 ++++ includes/logging/UploadLogFormatter.php | 49 ++++++ includes/revisiondelete/RevDelLogItem.php | 10 +- .../includes/logging/LogFormatterTest.php | 53 ++++++ 16 files changed, 452 insertions(+), 178 deletions(-) create mode 100644 includes/logging/UploadLogFormatter.php diff --git a/RELEASE-NOTES-1.25 b/RELEASE-NOTES-1.25 index 4f648f5195..f0d1c07f8f 100644 --- a/RELEASE-NOTES-1.25 +++ b/RELEASE-NOTES-1.25 @@ -125,6 +125,9 @@ production. Special:EditTags, generally accessed via the revision-deletion-like interface on history pages and Special:Log is likely to be more useful. * Added 'applychangetags' and 'changetags' user rights. +* (T35235) LogFormatter subclasses are now responsible for formatting the + parameters for API log event output. Extensions should implement the new + getParametersForApi() method in their log formatters. ==== External libraries ==== * MediaWiki now requires certain external libraries to be installed. In the past @@ -253,6 +256,18 @@ production. * Default type param for query list=watchlist and list=recentchanges has been changed from all types (e.g. including 'external') to 'edit|new|log'. * Added formatversion to format=json, still experimental. +* (T73020) Log event details are now always under a 'params' subkey for + list=logevents, and a 'logparams' subkey for list=watchlist and + list=recentchanges. +* Log event details are changing formatting: + * block events now report flags as an array rather than as a comma-separated + list. + * patrol events now report the 'auto' flag as a boolean (absent/empty string + for BC formats) rather than as an integer. + * rights events now report the old and new group lists as arrays rather than + as comma-separated lists. + * merge events use new-style formatting. + * delete/event and delete/revision events use new-style formatting. === Action API internal changes in 1.25 === * ApiHelp has been rewritten to support i18n and paginated HTML output. @@ -299,6 +314,8 @@ production. * ApiResult/ApiFormatBase "raw mode" is deprecated. * ApiFormatXml now assumes defaults and so on instead of throwing errors when metadata isn't set. +* (T35235) LogFormatter subclasses are now responsible for formatting log event + parameters for the API. * The following methods have been deprecated and may be removed in a future release: * ApiBase::getDescription @@ -341,6 +358,7 @@ production. * ApiResult::size * ApiResult::convertStatusToArray * ApiQueryImageInfo::getPropertyDescriptions + * ApiQueryLogEvents::addLogParams * The following classes have been deprecated and may be removed in a future release: * ApiQueryDeletedrevs diff --git a/autoload.php b/autoload.php index 38d1ac0818..ddd8254694 100644 --- a/autoload.php +++ b/autoload.php @@ -1276,6 +1276,7 @@ $wgAutoloadLocalClasses = array( 'UploadFromStash' => __DIR__ . '/includes/upload/UploadFromStash.php', 'UploadFromUrl' => __DIR__ . '/includes/upload/UploadFromUrl.php', 'UploadFromUrlJob' => __DIR__ . '/includes/jobqueue/jobs/UploadFromUrlJob.php', + 'UploadLogFormatter' => __DIR__ . '/includes/logging/UploadLogFormatter.php', 'UploadSourceAdapter' => __DIR__ . '/includes/Import.php', 'UploadSourceField' => __DIR__ . '/includes/specials/SpecialUpload.php', 'UploadStash' => __DIR__ . '/includes/upload/UploadStash.php', diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index c2d6c9512d..b08fe4d65a 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -6675,7 +6675,7 @@ $wgLogActions = array( ); /** - * The same as above, but here values are names of functions, + * The same as above, but here values are names of classes, * not messages. * @see LogPage::actionText * @see LogFormatter @@ -6693,9 +6693,9 @@ $wgLogActionsHandlers = array( 'patrol/patrol' => 'PatrolLogFormatter', 'rights/rights' => 'RightsLogFormatter', 'rights/autopromote' => 'RightsLogFormatter', - 'upload/upload' => 'LogFormatter', - 'upload/overwrite' => 'LogFormatter', - 'upload/revert' => 'LogFormatter', + 'upload/upload' => 'UploadLogFormatter', + 'upload/overwrite' => 'UploadLogFormatter', + 'upload/revert' => 'UploadLogFormatter', 'merge/merge' => 'MergeLogFormatter', 'tag/update' => 'TagLogFormatter', 'managetags/create' => 'LogFormatter', diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php index a626c8a132..b2397272b0 100644 --- a/includes/api/ApiQueryLogEvents.php +++ b/includes/api/ApiQueryLogEvents.php @@ -243,6 +243,7 @@ class ApiQueryLogEvents extends ApiQueryBase { } /** + * @deprecated since 1.25 Use LogFormatter::formatParametersForApi instead * @param ApiResult $result * @param array $vals * @param string $params @@ -255,142 +256,14 @@ class ApiQueryLogEvents extends ApiQueryBase { public static function addLogParams( $result, &$vals, $params, $type, $action, $ts, $legacy = false ) { - switch ( $type ) { - case 'move': - if ( $legacy ) { - $targetKey = 0; - $noredirKey = 1; - } else { - $targetKey = '4::target'; - $noredirKey = '5::noredir'; - } + wfDeprecated( __METHOD__, '1.25' ); - if ( isset( $params[$targetKey] ) ) { - $title = Title::newFromText( $params[$targetKey] ); - if ( $title ) { - $vals2 = array(); - ApiQueryBase::addTitleInfo( $vals2, $title, 'new_' ); - $vals[$type] = $vals2; - } - } - if ( isset( $params[$noredirKey] ) && $params[$noredirKey] ) { - $vals[$type]['suppressedredirect'] = ''; - } - $params = null; - break; - case 'patrol': - if ( $legacy ) { - $cur = 0; - $prev = 1; - $auto = 2; - } else { - $cur = '4::curid'; - $prev = '5::previd'; - $auto = '6::auto'; - } - $vals2 = array(); - $vals2['cur'] = $params[$cur]; - $vals2['prev'] = $params[$prev]; - $vals2['auto'] = $params[$auto]; - $vals[$type] = $vals2; - $params = null; - break; - case 'rights': - $vals2 = array(); - if ( $legacy ) { - list( $vals2['old'], $vals2['new'] ) = $params; - } else { - $vals2['new'] = implode( ', ', $params['5::newgroups'] ); - $vals2['old'] = implode( ', ', $params['4::oldgroups'] ); - } - $vals[$type] = $vals2; - $params = null; - break; - case 'block': - if ( $action == 'unblock' ) { - break; - } - if ( $legacy ) { - $durationKey = 0; - $flagsKey = 1; - } else { - $durationKey = '5::duration'; - $flagsKey = '6::flags'; - } - $vals2 = array(); - $vals2['duration'] = $params[$durationKey]; - $vals2['flags'] = isset( $params[$flagsKey] ) ? $params[$flagsKey] : ''; - - // Indefinite blocks have no expiry time - if ( SpecialBlock::parseExpiryInput( $params[$durationKey] ) !== 'infinity' ) { - $vals2['expiry'] = wfTimestamp( TS_ISO_8601, - strtotime( $params[$durationKey], wfTimestamp( TS_UNIX, $ts ) ) ); - } - $vals[$type] = $vals2; - $params = null; - break; - case 'upload': - if ( isset( $params['img_timestamp'] ) ) { - $params['img_timestamp'] = wfTimestamp( TS_ISO_8601, $params['img_timestamp'] ); - } - break; - case 'merge': - // replace the named parameter with numbered for backward compatibility - if ( isset( $params['4::dest'] ) ) { - $params[] = $params['4::dest']; - unset( $params['4::dest'] ); - } - if ( isset( $params['5::mergepoint'] ) ) { - $params[] = $params['5::mergepoint']; - unset( $params['5::mergepoint'] ); - } - break; - case 'delete': - if ( $action === 'event' || $action === 'revision' ) { - // replace the named parameter with numbered for backward compatibility - if ( $action === 'event' ) { - $idsKey = '4::ids'; - $ofieldKey = '5::ofield'; - $nfieldKey = '6::nfield'; - } else { - if ( isset( $params['4::type'] ) ) { - $params[] = $params['4::type']; - unset( $params['4::type'] ); - } - $idsKey = '5::ids'; - $ofieldKey = '6::ofield'; - $nfieldKey = '7::nfield'; - } - if ( isset( $params[$idsKey] ) ) { - $params[] = implode( ',', $params[$idsKey] ); - unset( $params[$idsKey] ); - } - if ( isset( $params[$ofieldKey] ) ) { - $params[] = 'ofield=' . $params[$ofieldKey]; - unset( $params[$ofieldKey] ); - } - if ( isset( $params[$nfieldKey] ) ) { - $params[] = 'nfield=' . $params[$nfieldKey]; - unset( $params[$nfieldKey] ); - } - } - break; - } - if ( !is_null( $params ) ) { - $logParams = array(); - // Keys like "4::paramname" can't be used for output so we change them to "paramname" - foreach ( $params as $key => $value ) { - if ( strpos( $key, ':' ) === false ) { - $logParams[$key] = $value; - continue; - } - $logParam = explode( ':', $key, 3 ); - $logParams[$logParam[2]] = $value; - } - ApiResult::setIndexedTagName( $logParams, 'param' ); - ApiResult::setIndexedTagNameOnSubarrays( $logParams, 'param' ); - $vals = array_merge( $vals, $logParams ); - } + $entry = new ManualLogEntry( $type, $action ); + $entry->setParameters( $params ); + $entry->setTimestamp( $ts ); + $entry->setLegacy( $legacy ); + $formatter = LogFormatter::newFromEntry( $entry ); + $vals['params'] = $formatter->formatParametersForApi(); return $vals; } @@ -423,15 +296,7 @@ class ApiQueryLogEvents extends ApiQueryBase { $vals['logpage'] = intval( $row->log_page ); } if ( $this->fld_details && $row->log_params !== '' ) { - self::addLogParams( - $this->getResult(), - $vals, - $logEntry->getParameters(), - $logEntry->getType(), - $logEntry->getSubtype(), - $logEntry->getTimestamp(), - $logEntry->isLegacy() - ); + $vals['params'] = LogFormatter::newFromRow( $row )->formatParametersForApi(); } } } diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php index 3dbfdf9f7e..28f8b7d9af 100644 --- a/includes/api/ApiQueryRecentChanges.php +++ b/includes/api/ApiQueryRecentChanges.php @@ -535,16 +535,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { $vals['logid'] = intval( $row->rc_logid ); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; - $logEntry = DatabaseLogEntry::newFromRow( $row ); - ApiQueryLogEvents::addLogParams( - $this->getResult(), - $vals, - $logEntry->getParameters(), - $logEntry->getType(), - $logEntry->getSubtype(), - $logEntry->getTimestamp(), - $logEntry->isLegacy() - ); + $vals['logparams'] = LogFormatter::newFromRow( $row )->formatParametersForApi(); } } diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php index 04eea54009..bd1ed0a1fc 100644 --- a/includes/api/ApiQueryWatchlist.php +++ b/includes/api/ApiQueryWatchlist.php @@ -412,16 +412,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { $vals['logid'] = intval( $row->rc_logid ); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; - $logEntry = DatabaseLogEntry::newFromRow( $row ); - ApiQueryLogEvents::addLogParams( - $this->getResult(), - $vals, - $logEntry->getParameters(), - $logEntry->getType(), - $logEntry->getSubtype(), - $logEntry->getTimestamp(), - $logEntry->isLegacy() - ); + $vals['logparams'] = LogFormatter::newFromRow( $row )->formatParametersForApi(); } } diff --git a/includes/logging/BlockLogFormatter.php b/includes/logging/BlockLogFormatter.php index 436fed84bb..38a279f5f5 100644 --- a/includes/logging/BlockLogFormatter.php +++ b/includes/logging/BlockLogFormatter.php @@ -168,4 +168,47 @@ class BlockLogFormatter extends LogFormatter { return $messages[$flag]; } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = $entry->getParameters(); + + static $map = array( + // While this looks wrong to be starting at 5 rather than 4, it's + // because getMessageParameters uses $4 for its own purposes. + '5::duration', + '6:array:flags', + '6::flags' => '6:array:flags', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + if ( isset( $params['6:array:flags'] ) && !is_array( $params['6:array:flags'] ) ) { + $params['6:array:flags'] = $params['6:array:flags'] === '' + ? array() + : explode( ',', $params['6:array:flags'] ); + } + + if ( isset( $params['5::duration'] ) && + SpecialBlock::parseExpiryInput( $params['5::duration'] ) !== wfGetDB( DB_SLAVE )->getInfinity() + ) { + $ts = wfTimestamp( TS_UNIX, $entry->getTimestamp() ); + $params[':timestamp:expiry'] = strtotime( $params['5::duration'], $ts ); + } + + return $params; + } + + public function formatParametersForApi() { + $ret = parent::formatParametersForApi(); + if ( isset( $ret['flags'] ) ) { + ApiResult::setIndexedTagName( $ret['flags'], 'f' ); + } + return $ret; + } + } diff --git a/includes/logging/DeleteLogFormatter.php b/includes/logging/DeleteLogFormatter.php index 7fe77b4ba3..f0598aa749 100644 --- a/includes/logging/DeleteLogFormatter.php +++ b/includes/logging/DeleteLogFormatter.php @@ -216,4 +216,67 @@ class DeleteLogFormatter extends LogFormatter { return ''; } } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = array(); + + $subtype = $this->entry->getSubtype(); + if ( in_array( $subtype, array( 'event', 'revision' ) ) ) { + $rawParams = $entry->getParameters(); + if ( $subtype === 'event' ) { + array_unshift( $rawParams, 'logging' ); + } + + static $map = array( + '4::type', + '5::ids', + '6::ofield', + '7::nfield', + '4::ids' => '5::ids', + '5::ofield' => '6::ofield', + '6::nfield' => '7::nfield', + ); + foreach ( $map as $index => $key ) { + if ( isset( $rawParams[$index] ) ) { + $rawParams[$key] = $rawParams[$index]; + unset( $rawParams[$index] ); + } + } + + $old = $this->parseBitField( $rawParams['6::ofield'] ); + $new = $this->parseBitField( $rawParams['7::nfield'] ); + if ( !is_array( $rawParams['5::ids'] ) ) { + $rawParams['5::ids'] = explode( ',', $rawParams['5::ids'] ); + } + + $params = array( + '::type' => $rawParams['4::type'], + ':array:ids' => $rawParams['5::ids'], + ':assoc:old' => array( 'bitmask' => $old ), + ':assoc:new' => array( 'bitmask' => $new ), + ); + + static $fields = array( + Revision::DELETED_TEXT => 'content', + Revision::DELETED_COMMENT => 'comment', + Revision::DELETED_USER => 'user', + Revision::DELETED_RESTRICTED => 'restricted', + ); + foreach ( $fields as $bit => $key ) { + $params[':assoc:old'][$key] = (bool)( $old & $bit ); + $params[':assoc:new'][$key] = (bool)( $new & $bit ); + } + } + + return $params; + } + + public function formatParametersForApi() { + $ret = parent::formatParametersForApi(); + if ( isset( $ret['ids'] ) ) { + ApiResult::setIndexedTagName( $ret['ids'], 'id' ); + } + return $ret; + } } diff --git a/includes/logging/LogFormatter.php b/includes/logging/LogFormatter.php index 6571888cfe..9c2fdd354a 100644 --- a/includes/logging/LogFormatter.php +++ b/includes/logging/LogFormatter.php @@ -472,7 +472,9 @@ class LogFormatter { continue; } list( $index, $type, ) = explode( ':', $key, 3 ); - $params[$index - 1] = $this->formatParameterValue( $type, $value ); + if ( ctype_digit( $index ) ) { + $params[$index - 1] = $this->formatParameterValue( $type, $value ); + } } /* Message class doesn't like non consecutive numbering. @@ -731,6 +733,120 @@ class LogFormatter { // problems with extensions return $this->getMessageParameters(); } + + /** + * Get the array of parameters, converted from legacy format if necessary. + * @since 1.25 + * @return array + */ + protected function getParametersForApi() { + return $this->entry->getParameters(); + } + + /** + * Format parameters for API output + * + * The result array should generally map named keys to values. Index and + * type should be omitted, e.g. "4::foo" should be returned as "foo" in the + * output. Values should generally be unformatted. + * + * Renames or removals of keys besides from the legacy numeric format to + * modern named style should be avoided. Any renames should be announced to + * the mediawiki-api-announce mailing list. + * + * @since 1.25 + * @return array + */ + public function formatParametersForApi() { + $logParams = array(); + foreach ( $this->getParametersForApi() as $key => $value ) { + $vals = explode( ':', $key, 3 ); + if ( count( $vals ) !== 3 ) { + $logParams[$key] = $value; + continue; + } + $logParams += $this->formatParameterValueForApi( $vals[2], $vals[1], $value ); + } + ApiResult::setIndexedTagName( $logParams, 'param' ); + ApiResult::setArrayType( $logParams, 'assoc' ); + + return $logParams; + } + + /** + * Format a single parameter value for API output + * + * @since 1.25 + * @param string $name + * @param string $type + * @param string $value + * @return array + */ + protected function formatParameterValueForApi( $name, $type, $value ) { + $type = strtolower( trim( $type ) ); + switch ( $type ) { + case 'bool': + $value = (bool)$value; + break; + + case 'number': + if ( ctype_digit( $value ) ) { + $value = (int)$value; + } else { + $value = (float)$value; + } + break; + + case 'array': + case 'assoc': + case 'kvp': + if ( is_array( $value ) ) { + ApiResult::setArrayType( $value, $type ); + } + break; + + case 'timestamp': + $value = wfTimestamp( TS_ISO_8601, $value ); + break; + + case 'msg': + case 'msg-content': + $msg = $this->msg( $value ); + if ( $type === 'msg-content' ) { + $msg->inContentLanguage(); + } + $value = array(); + $value["{$name}_key"] = $msg->getKey(); + if ( $msg->getParams() ) { + $value["{$name}_params"] = $msg->getParams(); + } + $value["{$name}_text"] = $msg->text(); + return $value; + + case 'title': + case 'title-link': + $title = Title::newFromText( $value ); + if ( $title ) { + $value = array(); + ApiQueryBase::addTitleInfo( $value, $title, "{$name}_" ); + } + return $value; + + case 'user': + case 'user-link': + $user = User::newFromName( $value ); + if ( $user ) { + $value = $user->getName(); + } + break; + + default: + // do nothing + break; + } + + return array( $name => $value ); + } } /** diff --git a/includes/logging/MergeLogFormatter.php b/includes/logging/MergeLogFormatter.php index 6763dbd19f..36e383b069 100644 --- a/includes/logging/MergeLogFormatter.php +++ b/includes/logging/MergeLogFormatter.php @@ -68,4 +68,24 @@ class MergeLogFormatter extends LogFormatter { return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = $entry->getParameters(); + + static $map = array( + '4:title:dest', + '5:timestamp:mergepoint', + '4::dest' => '4:title:dest', + '5::mergepoint' => '5:timestamp:mergepoint', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + return $params; + } } diff --git a/includes/logging/MoveLogFormatter.php b/includes/logging/MoveLogFormatter.php index 35da113ab5..e60708db62 100644 --- a/includes/logging/MoveLogFormatter.php +++ b/includes/logging/MoveLogFormatter.php @@ -85,4 +85,25 @@ class MoveLogFormatter extends LogFormatter { return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = $entry->getParameters(); + + static $map = array( + '4:title:target', + '5:bool:suppressredirect', + '4::target' => '4:title:target', + '5::noredir' => '5:bool:suppressredirect', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + return $params; + } + } diff --git a/includes/logging/PatrolLogFormatter.php b/includes/logging/PatrolLogFormatter.php index 2abaf17359..00337432cc 100644 --- a/includes/logging/PatrolLogFormatter.php +++ b/includes/logging/PatrolLogFormatter.php @@ -62,4 +62,24 @@ class PatrolLogFormatter extends LogFormatter { return $params; } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = $entry->getParameters(); + + static $map = array( + '4::curid', + '5::previd', + '6:bool:auto', + '6::auto' => '6:bool:auto', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + return $params; + } } diff --git a/includes/logging/RightsLogFormatter.php b/includes/logging/RightsLogFormatter.php index ac252aebc3..597bec58e9 100644 --- a/includes/logging/RightsLogFormatter.php +++ b/includes/logging/RightsLogFormatter.php @@ -110,4 +110,35 @@ class RightsLogFormatter extends LogFormatter { return $params; } + + protected function getParametersForApi() { + $entry = $this->entry; + $params = $entry->getParameters(); + + static $map = array( + '4:array:oldgroups', + '5:array:newgroups', + '4::oldgroups' => '4:array:oldgroups', + '5::newgroups' => '5:array:newgroups', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + return $params; + } + + public function formatParametersForApi() { + $ret = parent::formatParametersForApi(); + if ( isset( $ret['oldgroups'] ) ) { + ApiResult::setIndexedTagName( $ret['oldgroups'], 'g' ); + } + if ( isset( $ret['newgroups'] ) ) { + ApiResult::setIndexedTagName( $ret['newgroups'], 'g' ); + } + return $ret; + } } diff --git a/includes/logging/UploadLogFormatter.php b/includes/logging/UploadLogFormatter.php new file mode 100644 index 0000000000..52961dc4aa --- /dev/null +++ b/includes/logging/UploadLogFormatter.php @@ -0,0 +1,49 @@ +entry; + $params = $entry->getParameters(); + + static $map = array( + 'img_timestamp' => ':timestamp:img_timestamp', + ); + foreach ( $map as $index => $key ) { + if ( isset( $params[$index] ) ) { + $params[$key] = $params[$index]; + unset( $params[$index] ); + } + } + + return $params; + } + +} diff --git a/includes/revisiondelete/RevDelLogItem.php b/includes/revisiondelete/RevDelLogItem.php index 5c8b8c9d8f..49adf204a8 100644 --- a/includes/revisiondelete/RevDelLogItem.php +++ b/includes/revisiondelete/RevDelLogItem.php @@ -124,15 +124,7 @@ class RevDelLogItem extends RevDelItem { : array(); if ( LogEventsList::userCan( $this->row, LogPage::DELETED_ACTION, $user ) ) { - ApiQueryLogEvents::addLogParams( - $result, - $ret, - $logEntry->getParameters(), - $logEntry->getType(), - $logEntry->getSubtype(), - $logEntry->getTimestamp(), - $logEntry->isLegacy() - ); + $ret['params'] = LogFormatter::newFromEntry( $logEntry )->formatParametersForApi(); } if ( LogEventsList::userCan( $this->row, LogPage::DELETED_USER, $user ) ) { $ret += array( diff --git a/tests/phpunit/includes/logging/LogFormatterTest.php b/tests/phpunit/includes/logging/LogFormatterTest.php index 6210d0985c..515990e64a 100644 --- a/tests/phpunit/includes/logging/LogFormatterTest.php +++ b/tests/phpunit/includes/logging/LogFormatterTest.php @@ -239,4 +239,57 @@ class LogFormatterTest extends MediaWikiLangTestCase { $this->assertEquals( $comment, $formatter->getComment() ); } + + /** + * @dataProvider provideApiParamFormatting + * @covers LogFormatter::formatParametersForApi + * @covers LogFormatter::formatParameterValueForApi + */ + public function testApiParamFormatting( $key, $value, $expected ) { + $entry = $this->newLogEntry( 'param', array( $key => $value ) ); + $formatter = LogFormatter::newFromEntry( $entry ); + $formatter->setContext( $this->context ); + + ApiResult::setIndexedTagName( $expected, 'param' ); + ApiResult::setArrayType( $expected, 'assoc' ); + + $this->assertEquals( $expected, $formatter->formatParametersForApi() ); + } + + public static function provideApiParamFormatting() { + return array( + array( 0, 'value', array( 'value' ) ), + array( 'named', 'value', array( 'named' => 'value' ) ), + array( '::key', 'value', array( 'key' => 'value' ) ), + array( '4::key', 'value', array( 'key' => 'value' ) ), + array( '4:raw:key', 'value', array( 'key' => 'value' ) ), + array( '4:plain:key', 'value', array( 'key' => 'value' ) ), + array( '4:bool:key', '1', array( 'key' => true ) ), + array( '4:bool:key', '0', array( 'key' => false ) ), + array( '4:number:key', '123', array( 'key' => 123 ) ), + array( '4:number:key', '123.5', array( 'key' => 123.5 ) ), + array( '4:array:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'array' ) ) ), + array( '4:assoc:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'assoc' ) ) ), + array( '4:kvp:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'kvp' ) ) ), + array( '4:timestamp:key', '20150102030405', array( 'key' => '2015-01-02T03:04:05Z' ) ), + array( '4:msg:key', 'parentheses', array( + 'key_key' => 'parentheses', + 'key_text' => wfMessage( 'parentheses' )->text(), + ) ), + array( '4:msg-content:key', 'parentheses', array( + 'key_key' => 'parentheses', + 'key_text' => wfMessage( 'parentheses' )->inContentLanguage()->text(), + ) ), + array( '4:title:key', 'project:foo', array( + 'key_ns' => NS_PROJECT, + 'key_title' => Title::newFromText( 'project:foo' )->getFullText(), + ) ), + array( '4:title-link:key', 'project:foo', array( + 'key_ns' => NS_PROJECT, + 'key_title' => Title::newFromText( 'project:foo' )->getFullText(), + ) ), + array( '4:user:key', 'foo', array( 'key' => 'Foo' ) ), + array( '4:user-link:key', 'foo', array( 'key' => 'Foo' ) ), + ); + } } -- 2.20.1