API: Move parameter formatting into LogFormatter
authorBrad Jorsch <bjorsch@wikimedia.org>
Sun, 10 Aug 2014 10:25:29 +0000 (11:25 +0100)
committerLegoktm <legoktm.wikipedia@gmail.com>
Fri, 17 Apr 2015 04:59:41 +0000 (04:59 +0000)
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

16 files changed:
RELEASE-NOTES-1.25
autoload.php
includes/DefaultSettings.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryWatchlist.php
includes/logging/BlockLogFormatter.php
includes/logging/DeleteLogFormatter.php
includes/logging/LogFormatter.php
includes/logging/MergeLogFormatter.php
includes/logging/MoveLogFormatter.php
includes/logging/PatrolLogFormatter.php
includes/logging/RightsLogFormatter.php
includes/logging/UploadLogFormatter.php [new file with mode: 0644]
includes/revisiondelete/RevDelLogItem.php
tests/phpunit/includes/logging/LogFormatterTest.php

index 4f648f5..f0d1c07 100644 (file)
@@ -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
index 38d1ac0..ddd8254 100644 (file)
@@ -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',
index c2d6c95..b08fe4d 100644 (file)
@@ -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',
index a626c8a..b239727 100644 (file)
@@ -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();
                                }
                        }
                }
index 3dbfdf9..28f8b7d 100644 (file)
@@ -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();
                        }
                }
 
index 04eea54..bd1ed0a 100644 (file)
@@ -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();
                        }
                }
 
index 436fed8..38a279f 100644 (file)
@@ -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;
+       }
+
 }
index 7fe77b4..f0598aa 100644 (file)
@@ -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;
+       }
 }
index 6571888..9c2fdd3 100644 (file)
@@ -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 );
+       }
 }
 
 /**
index 6763dbd..36e383b 100644 (file)
@@ -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;
+       }
 }
index 35da113..e60708d 100644 (file)
@@ -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;
+       }
+
 }
index 2abaf17..0033743 100644 (file)
@@ -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;
+       }
 }
index ac252ae..597bec5 100644 (file)
@@ -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 (file)
index 0000000..52961dc
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Formatter for upload log entries.
+ *
+ * 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
+ *
+ * @file
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ * @since 1.25
+ */
+
+/**
+ * This class formats upload log entries.
+ *
+ * @since 1.25
+ */
+class UploadLogFormatter extends LogFormatter {
+
+       protected function getParametersForApi() {
+               $entry = $this->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;
+       }
+
+}
index 5c8b8c9..49adf20 100644 (file)
@@ -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(
index 6210d09..515990e 100644 (file)
@@ -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' ) ),
+               );
+       }
 }