MediaWiki  master
LogFormatter.php
Go to the documentation of this file.
00001 <?php
00033 class LogFormatter {
00034         // Audience options for viewing usernames, comments, and actions
00035         const FOR_PUBLIC = 1;
00036         const FOR_THIS_USER = 2;
00037 
00038         // Static->
00039 
00045         public static function newFromEntry( LogEntry $entry ) {
00046                 global $wgLogActionsHandlers;
00047                 $fulltype = $entry->getFullType();
00048                 $wildcard = $entry->getType() . '/*';
00049                 $handler = '';
00050 
00051                 if ( isset( $wgLogActionsHandlers[$fulltype] ) ) {
00052                         $handler = $wgLogActionsHandlers[$fulltype];
00053                 } elseif ( isset( $wgLogActionsHandlers[$wildcard] ) ) {
00054                         $handler = $wgLogActionsHandlers[$wildcard];
00055                 }
00056 
00057                 if ( $handler !== '' && is_string( $handler ) && class_exists( $handler ) ) {
00058                         return new $handler( $entry );
00059                 }
00060 
00061                 return new LegacyLogFormatter( $entry );
00062         }
00063 
00071         public static function newFromRow( $row ) {
00072                 return self::newFromEntry( DatabaseLogEntry::newFromRow( $row ) );
00073         }
00074 
00075         // Nonstatic->
00076 
00078         protected $entry;
00079 
00081         protected $audience = self::FOR_PUBLIC;
00082 
00084         protected $linkFlood = false;
00085 
00093         protected $plaintext = false;
00094 
00095         protected $irctext = false;
00096 
00097         protected function __construct( LogEntry $entry ) {
00098                 $this->entry = $entry;
00099                 $this->context = RequestContext::getMain();
00100         }
00101 
00106         public function setContext( IContextSource $context ) {
00107                 $this->context = $context;
00108         }
00109 
00116         public function setAudience( $audience ) {
00117                 $this->audience = ( $audience == self::FOR_THIS_USER )
00118                         ? self::FOR_THIS_USER
00119                         : self::FOR_PUBLIC;
00120         }
00121 
00127         protected function canView( $field ) {
00128                 if ( $this->audience == self::FOR_THIS_USER ) {
00129                         return LogEventsList::userCanBitfield(
00130                                 $this->entry->getDeleted(), $field, $this->context->getUser() );
00131                 } else {
00132                         return !$this->entry->isDeleted( $field );
00133                 }
00134         }
00135 
00142         public function setShowUserToolLinks( $value ) {
00143                 $this->linkFlood = $value;
00144         }
00145 
00153         public function getPlainActionText() {
00154                 $this->plaintext = true;
00155                 $text = $this->getActionText();
00156                 $this->plaintext = false;
00157                 return $text;
00158         }
00159 
00166         public function getIRCActionComment() {
00167                 $actionComment = $this->getIRCActionText();
00168                 $comment = $this->entry->getComment();
00169 
00170                 if ( $comment != '' ) {
00171                         if ( $actionComment == '' ) {
00172                                 $actionComment = $comment;
00173                         } else {
00174                                 $actionComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment;
00175                         }
00176                 }
00177 
00178                 return $actionComment;
00179         }
00180 
00187         public function getIRCActionText() {
00188                 $this->plaintext = true;
00189                 $this->irctext = true;
00190 
00191                 $entry = $this->entry;
00192                 $parameters = $entry->getParameters();
00193                 // @see LogPage::actionText()
00194                 // Text of title the action is aimed at.
00195                 $target = $entry->getTarget()->getPrefixedText() ;
00196                 $text = null;
00197                 switch( $entry->getType() ) {
00198                         case 'move':
00199                                 switch( $entry->getSubtype() ) {
00200                                         case 'move':
00201                                                 $movesource =  $parameters['4::target'];
00202                                                 $text = wfMessage( '1movedto2' )
00203                                                         ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
00204                                                 break;
00205                                         case 'move_redir':
00206                                                 $movesource =  $parameters['4::target'];
00207                                                 $text = wfMessage( '1movedto2_redir' )
00208                                                         ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
00209                                                 break;
00210                                         case 'move-noredirect':
00211                                                 break;
00212                                         case 'move_redir-noredirect':
00213                                                 break;
00214                                 }
00215                                 break;
00216 
00217                         case 'delete':
00218                                 switch( $entry->getSubtype() ) {
00219                                         case 'delete':
00220                                                 $text = wfMessage( 'deletedarticle' )
00221                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00222                                                 break;
00223                                         case 'restore':
00224                                                 $text = wfMessage( 'undeletedarticle' )
00225                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00226                                                 break;
00227                                         //case 'revision': // Revision deletion
00228                                         //case 'event': // Log deletion
00229                                                 // see https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/LogPage.php?&pathrev=97044&r1=97043&r2=97044
00230                                         //default:
00231                                 }
00232                                 break;
00233 
00234                         case 'patrol':
00235                                 // https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/PatrolLog.php?&pathrev=97495&r1=97494&r2=97495
00236                                 // Create a diff link to the patrolled revision
00237                                 if ( $entry->getSubtype() === 'patrol' ) {
00238                                         $diffLink = htmlspecialchars(
00239                                                 wfMessage( 'patrol-log-diff', $parameters['4::curid'] )
00240                                                         ->inContentLanguage()->text() );
00241                                         $text = wfMessage( 'patrol-log-line', $diffLink, "[[$target]]", "" )
00242                                                 ->inContentLanguage()->text();
00243                                 } else {
00244                                         // broken??
00245                                 }
00246                                 break;
00247 
00248                         case 'protect':
00249                                 switch( $entry->getSubtype() ) {
00250                                 case 'protect':
00251                                         $text = wfMessage( 'protectedarticle' )
00252                                                 ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
00253                                         break;
00254                                 case 'unprotect':
00255                                         $text = wfMessage( 'unprotectedarticle' )
00256                                                 ->rawParams( $target )->inContentLanguage()->escaped();
00257                                         break;
00258                                 case 'modify':
00259                                         $text = wfMessage( 'modifiedarticleprotection' )
00260                                                 ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
00261                                         break;
00262                                 }
00263                                 break;
00264 
00265                         case 'newusers':
00266                                 switch( $entry->getSubtype() ) {
00267                                         case 'newusers':
00268                                         case 'create':
00269                                                 $text = wfMessage( 'newuserlog-create-entry' )
00270                                                         ->inContentLanguage()->escaped();
00271                                                 break;
00272                                         case 'create2':
00273                                                 $text = wfMessage( 'newuserlog-create2-entry' )
00274                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00275                                                 break;
00276                                         case 'autocreate':
00277                                                 $text = wfMessage( 'newuserlog-autocreate-entry' )
00278                                                         ->inContentLanguage()->escaped();
00279                                                 break;
00280                                 }
00281                                 break;
00282 
00283                         case 'upload':
00284                                 switch( $entry->getSubtype() ) {
00285                                         case 'upload':
00286                                                 $text = wfMessage( 'uploadedimage' )
00287                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00288                                                 break;
00289                                         case 'overwrite':
00290                                                 $text = wfMessage( 'overwroteimage' )
00291                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00292                                                 break;
00293                                 }
00294                                 break;
00295 
00296                         case 'rights':
00297                                 if ( count( $parameters['4::oldgroups'] ) ) {
00298                                         $oldgroups = implode( ', ', $parameters['4::oldgroups'] );
00299                                 } else {
00300                                         $oldgroups = wfMessage( 'rightsnone' )->inContentLanguage()->escaped();
00301                                 }
00302                                 if ( count( $parameters['5::newgroups'] ) ) {
00303                                         $newgroups = implode( ', ', $parameters['5::newgroups'] );
00304                                 } else {
00305                                         $newgroups = wfMessage( 'rightsnone' )->inContentLanguage()->escaped();
00306                                 }
00307                                 switch( $entry->getSubtype() ) {
00308                                         case 'rights':
00309                                                 $text = wfMessage( 'rightslogentry' )
00310                                                         ->rawParams( $target, $oldgroups, $newgroups )->inContentLanguage()->escaped();
00311                                                 break;
00312                                         case 'autopromote':
00313                                                 $text = wfMessage( 'rightslogentry-autopromote' )
00314                                                         ->rawParams( $target, $oldgroups, $newgroups )->inContentLanguage()->escaped();
00315                                                 break;
00316                                 }
00317                                 break;
00318 
00319                         // case 'suppress' --private log -- aaron  (sign your messages so we know who to blame in a few years :-D)
00320                         // default:
00321                 }
00322                 if( is_null( $text ) ) {
00323                         $text = $this->getPlainActionText();
00324                 }
00325 
00326                 $this->plaintext = false;
00327                 $this->irctext = false;
00328                 return $text;
00329         }
00330 
00335         public function getActionText() {
00336                 if ( $this->canView( LogPage::DELETED_ACTION ) ) {
00337                         $element = $this->getActionMessage();
00338                         if ( $element instanceof Message ) {
00339                                 $element = $this->plaintext ? $element->text() : $element->escaped();
00340                         }
00341                         if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00342                                 $element = $this->styleRestricedElement( $element );
00343                         }
00344                 } else {
00345                         $performer = $this->getPerformerElement() . $this->msg( 'word-separator' )->text();
00346                         $element = $performer . $this->getRestrictedElement( 'rev-deleted-event' );
00347                 }
00348 
00349                 return $element;
00350         }
00351 
00358         protected function getActionMessage() {
00359                 $message = $this->msg( $this->getMessageKey() );
00360                 $message->params( $this->getMessageParameters() );
00361                 return $message;
00362         }
00363 
00371         protected function getMessageKey() {
00372                 $type = $this->entry->getType();
00373                 $subtype = $this->entry->getSubtype();
00374 
00375                 return "logentry-$type-$subtype";
00376         }
00377 
00383         public function getActionLinks() {
00384                 return '';
00385         }
00386 
00392         protected function extractParameters() {
00393                 $entry = $this->entry;
00394                 $params = array();
00395 
00396                 if ( $entry->isLegacy() ) {
00397                         foreach ( $entry->getParameters() as $index => $value ) {
00398                                 $params[$index + 3] = $value;
00399                         }
00400                 }
00401 
00402                 // Filter out parameters which are not in format #:foo
00403                 foreach ( $entry->getParameters() as $key => $value ) {
00404                         if ( strpos( $key, ':' ) === false ) continue;
00405                         list( $index, $type, $name ) = explode( ':', $key, 3 );
00406                         $params[$index - 1] = $value;
00407                 }
00408 
00409                 /* Message class doesn't like non consecutive numbering.
00410                  * Fill in missing indexes with empty strings to avoid
00411                  * incorrect renumbering.
00412                  */
00413                 if ( count( $params ) ) {
00414                         $max = max( array_keys( $params ) );
00415                         for ( $i = 4; $i < $max; $i++ ) {
00416                                 if ( !isset( $params[$i] ) ) {
00417                                         $params[$i] = '';
00418                                 }
00419                         }
00420                 }
00421                 return $params;
00422         }
00423 
00433         protected function getMessageParameters() {
00434                 if ( isset( $this->parsedParameters ) ) {
00435                         return $this->parsedParameters;
00436                 }
00437 
00438                 $entry = $this->entry;
00439                 $params = $this->extractParameters();
00440                 $params[0] = Message::rawParam( $this->getPerformerElement() );
00441                 $params[1] = $entry->getPerformer()->getName();
00442                 $params[2] = Message::rawParam( $this->makePageLink( $entry->getTarget() ) );
00443 
00444                 // Bad things happens if the numbers are not in correct order
00445                 ksort( $params );
00446                 return $this->parsedParameters = $params;
00447         }
00448 
00457         protected function makePageLink( Title $title = null, $parameters = array() ) {
00458                 if ( !$this->plaintext ) {
00459                         $link = Linker::link( $title, null, array(), $parameters );
00460                 } else {
00461                         if ( !$title instanceof Title ) {
00462                                 throw new MWException( "Expected title, got null" );
00463                         }
00464                         $link = '[[' . $title->getPrefixedText() . ']]';
00465                 }
00466                 return $link;
00467         }
00468 
00475         public function getPerformerElement() {
00476                 if ( $this->canView( LogPage::DELETED_USER ) ) {
00477                         $performer = $this->entry->getPerformer();
00478                         $element = $this->makeUserLink( $performer );
00479                         if ( $this->entry->isDeleted( LogPage::DELETED_USER ) ) {
00480                                 $element = $this->styleRestricedElement( $element );
00481                         }
00482                 } else {
00483                         $element = $this->getRestrictedElement( 'rev-deleted-user' );
00484                 }
00485 
00486                 return $element;
00487         }
00488 
00493         public function getComment() {
00494                 if ( $this->canView( LogPage::DELETED_COMMENT ) ) {
00495                         $comment = Linker::commentBlock( $this->entry->getComment() );
00496                         // No hard coded spaces thanx
00497                         $element = ltrim( $comment );
00498                         if ( $this->entry->isDeleted( LogPage::DELETED_COMMENT ) ) {
00499                                 $element = $this->styleRestricedElement( $element );
00500                         }
00501                 } else {
00502                         $element = $this->getRestrictedElement( 'rev-deleted-comment' );
00503                 }
00504 
00505                 return $element;
00506         }
00507 
00513         protected function getRestrictedElement( $message ) {
00514                 if ( $this->plaintext ) {
00515                         return $this->msg( $message )->text();
00516                 }
00517 
00518                 $content =  $this->msg( $message )->escaped();
00519                 $attribs = array( 'class' => 'history-deleted' );
00520                 return Html::rawElement( 'span', $attribs, $content );
00521         }
00522 
00528         protected function styleRestricedElement( $content ) {
00529                 if ( $this->plaintext ) {
00530                         return $content;
00531                 }
00532                 $attribs = array( 'class' => 'history-deleted' );
00533                 return Html::rawElement( 'span', $attribs, $content );
00534         }
00535 
00542         protected function msg( $key ) {
00543                 return $this->context->msg( $key );
00544         }
00545 
00546         protected function makeUserLink( User $user ) {
00547                 if ( $this->plaintext ) {
00548                         $element = $user->getName();
00549                 } else {
00550                         $element = Linker::userLink(
00551                                 $user->getId(),
00552                                 $user->getName()
00553                         );
00554 
00555                         if ( $this->linkFlood ) {
00556                                 $element .= Linker::userToolLinksRedContribs(
00557                                         $user->getId(),
00558                                         $user->getName(),
00559                                         $user->getEditCount()
00560                                 );
00561                         }
00562                 }
00563                 return $element;
00564         }
00565 
00569         public function getPreloadTitles() {
00570                 return array();
00571         }
00572 
00573 }
00574 
00584 class LegacyLogFormatter extends LogFormatter {
00585 
00595         private $comment = null;
00596 
00604         private $revert = null;
00605 
00606         public function getComment() {
00607                 if ( $this->comment === null ) {
00608                         $this->comment = parent::getComment();
00609                 }
00610 
00611                 // Make sure we execute the LogLine hook so that we immediately return
00612                 // the correct value.
00613                 if ( $this->revert === null ) {
00614                         $this->getActionLinks();
00615                 }
00616 
00617                 return $this->comment;
00618         }
00619 
00620         protected function getActionMessage() {
00621                 $entry = $this->entry;
00622                 $action = LogPage::actionText(
00623                         $entry->getType(),
00624                         $entry->getSubtype(),
00625                         $entry->getTarget(),
00626                         $this->plaintext ? null : $this->context->getSkin(),
00627                         (array)$entry->getParameters(),
00628                         !$this->plaintext // whether to filter [[]] links
00629                 );
00630 
00631                 $performer = $this->getPerformerElement();
00632                 if ( !$this->irctext ) {
00633                         $action = $performer .  $this->msg( 'word-separator' )->text() . $action;
00634                 }
00635 
00636                 return $action;
00637         }
00638 
00639         public function getActionLinks() {
00640                 if ( $this->revert !== null ) {
00641                         return $this->revert;
00642                 }
00643 
00644                 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00645                         return $this->revert = '';
00646                 }
00647 
00648                 $title = $this->entry->getTarget();
00649                 $type = $this->entry->getType();
00650                 $subtype = $this->entry->getSubtype();
00651 
00652                 // Show unblock/change block link
00653                 if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) {
00654                         if ( !$this->context->getUser()->isAllowed( 'block' ) ) {
00655                                 return '';
00656                         }
00657 
00658                         $links = array(
00659                                 Linker::linkKnown(
00660                                         SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ),
00661                                         $this->msg( 'unblocklink' )->escaped()
00662                                 ),
00663                                 Linker::linkKnown(
00664                                         SpecialPage::getTitleFor( 'Block', $title->getDBkey() ),
00665                                         $this->msg( 'change-blocklink' )->escaped()
00666                                 )
00667                         );
00668                         return $this->msg( 'parentheses' )->rawParams(
00669                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00670                 // Show change protection link
00671                 } elseif ( $type == 'protect' && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) ) {
00672                         $links = array(
00673                                 Linker::link( $title,
00674                                         $this->msg( 'hist' )->escaped(),
00675                                         array(),
00676                                         array(
00677                                                 'action' => 'history',
00678                                                 'offset' => $this->entry->getTimestamp()
00679                                         )
00680                                 )
00681                         );
00682                         if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
00683                                 $links[] = Linker::linkKnown(
00684                                         $title,
00685                                         $this->msg( 'protect_change' )->escaped(),
00686                                         array(),
00687                                         array( 'action' => 'protect' )
00688                                 );
00689                         }
00690                         return $this->msg( 'parentheses' )->rawParams(
00691                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00692                 // Show unmerge link
00693                 } elseif( $type == 'merge' && $subtype == 'merge' ) {
00694                         if ( !$this->context->getUser()->isAllowed( 'mergehistory' ) ) {
00695                                 return '';
00696                         }
00697 
00698                         $params = $this->extractParameters();
00699                         $revert = Linker::linkKnown(
00700                                 SpecialPage::getTitleFor( 'MergeHistory' ),
00701                                 $this->msg( 'revertmerge' )->escaped(),
00702                                 array(),
00703                                 array(
00704                                         'target' => $params[3],
00705                                         'dest' => $title->getPrefixedDBkey(),
00706                                         'mergepoint' => $params[4]
00707                                 )
00708                         );
00709                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00710                 }
00711 
00712                 // Do nothing. The implementation is handled by the hook modifiying the
00713                 // passed-by-ref parameters. This also changes the default value so that
00714                 // getComment() and getActionLinks() do not call them indefinitely.
00715                 $this->revert = '';
00716 
00717                 // This is to populate the $comment member of this instance so that it
00718                 // can be modified when calling the hook just below.
00719                 if ( $this->comment === null ) {
00720                         $this->getComment();
00721                 }
00722 
00723                 $params = $this->entry->getParameters();
00724 
00725                 wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
00726                         &$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
00727 
00728                 return $this->revert;
00729         }
00730 }
00731 
00736 class MoveLogFormatter extends LogFormatter {
00737         public function getPreloadTitles() {
00738                 $params = $this->extractParameters();
00739                 return array( Title::newFromText( $params[3] ) );
00740         }
00741 
00742         protected function getMessageKey() {
00743                 $key = parent::getMessageKey();
00744                 $params = $this->getMessageParameters();
00745                 if ( isset( $params[4] ) && $params[4] === '1' ) {
00746                         $key .= '-noredirect';
00747                 }
00748                 return $key;
00749         }
00750 
00751         protected function getMessageParameters() {
00752                 $params = parent::getMessageParameters();
00753                 $oldname = $this->makePageLink( $this->entry->getTarget(), array( 'redirect' => 'no' ) );
00754                 $newname = $this->makePageLink( Title::newFromText( $params[3] ) );
00755                 $params[2] = Message::rawParam( $oldname );
00756                 $params[3] = Message::rawParam( $newname );
00757                 return $params;
00758         }
00759 
00760         public function getActionLinks() {
00761                 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
00762                         || $this->entry->getSubtype() !== 'move'
00763                         || !$this->context->getUser()->isAllowed( 'move' ) )
00764                 {
00765                         return '';
00766                 }
00767 
00768                 $params = $this->extractParameters();
00769                 $destTitle = Title::newFromText( $params[3] );
00770                 if ( !$destTitle ) {
00771                         return '';
00772                 }
00773 
00774                 $revert = Linker::linkKnown(
00775                         SpecialPage::getTitleFor( 'Movepage' ),
00776                         $this->msg( 'revertmove' )->escaped(),
00777                         array(),
00778                         array(
00779                                 'wpOldTitle' => $destTitle->getPrefixedDBkey(),
00780                                 'wpNewTitle' => $this->entry->getTarget()->getPrefixedDBkey(),
00781                                 'wpReason'   => $this->msg( 'revertmove' )->inContentLanguage()->text(),
00782                                 'wpMovetalk' => 0
00783                         )
00784                 );
00785                 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00786         }
00787 }
00788 
00793 class DeleteLogFormatter extends LogFormatter {
00794         protected function getMessageKey() {
00795                 $key = parent::getMessageKey();
00796                 if ( in_array( $this->entry->getSubtype(), array( 'event', 'revision' ) ) ) {
00797                         if ( count( $this->getMessageParameters() ) < 5 ) {
00798                                 return "$key-legacy";
00799                         }
00800                 }
00801                 return $key;
00802         }
00803 
00804         protected function getMessageParameters() {
00805                 if ( isset( $this->parsedParametersDeleteLog ) ) {
00806                         return $this->parsedParametersDeleteLog;
00807                 }
00808 
00809                 $params = parent::getMessageParameters();
00810                 $subtype = $this->entry->getSubtype();
00811                 if ( in_array( $subtype, array( 'event', 'revision' ) ) ) {
00812                         if (
00813                                 ($subtype === 'event' && count( $params ) === 6 ) ||
00814                                 ($subtype === 'revision' && isset( $params[3] ) && $params[3] === 'revision' )
00815                         ) {
00816                                 $paramStart = $subtype === 'revision' ? 4 : 3;
00817 
00818                                 $old = $this->parseBitField( $params[$paramStart+1] );
00819                                 $new = $this->parseBitField( $params[$paramStart+2] );
00820                                 list( $hid, $unhid, $extra ) = RevisionDeleter::getChanges( $new, $old );
00821                                 $changes = array();
00822                                 foreach ( $hid as $v ) {
00823                                         $changes[] = $this->msg( "$v-hid" )->plain();
00824                                 }
00825                                 foreach ( $unhid as $v ) {
00826                                         $changes[] = $this->msg( "$v-unhid" )->plain();
00827                                 }
00828                                 foreach ( $extra as $v ) {
00829                                         $changes[] = $this->msg( $v )->plain();
00830                                 }
00831                                 $changeText =  $this->context->getLanguage()->listToText( $changes );
00832 
00833 
00834                                 $newParams = array_slice( $params, 0, 3 );
00835                                 $newParams[3] = $changeText;
00836                                 $count = count( explode( ',', $params[$paramStart] ) );
00837                                 $newParams[4] = $this->context->getLanguage()->formatNum( $count );
00838                                 return $this->parsedParametersDeleteLog = $newParams;
00839                         } else {
00840                                 return $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 );
00841                         }
00842                 }
00843 
00844                 return $this->parsedParametersDeleteLog = $params;
00845         }
00846 
00847         protected function parseBitField( $string ) {
00848                 // Input is like ofield=2134 or just the number
00849                 if ( strpos( $string, 'field=' ) === 1 ) {
00850                         list( , $field ) = explode( '=', $string );
00851                         return (int) $field;
00852                 } else {
00853                         return (int) $string;
00854                 }
00855         }
00856 
00857         public function getActionLinks() {
00858                 $user = $this->context->getUser();
00859                 if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00860                         return '';
00861                 }
00862 
00863                 switch ( $this->entry->getSubtype() ) {
00864                 case 'delete': // Show undelete link
00865                         if( $user->isAllowed( 'undelete' ) ) {
00866                                 $message = 'undeletelink';
00867                         } else {
00868                                 $message = 'undeleteviewlink';
00869                         }
00870                         $revert = Linker::linkKnown(
00871                                 SpecialPage::getTitleFor( 'Undelete' ),
00872                                 $this->msg( $message )->escaped(),
00873                                 array(),
00874                                 array( 'target' => $this->entry->getTarget()->getPrefixedDBkey() )
00875                          );
00876                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00877 
00878                 case 'revision': // If an edit was hidden from a page give a review link to the history
00879                         $params = $this->extractParameters();
00880                         if ( !isset( $params[3] ) || !isset( $params[4] ) ) {
00881                                 return '';
00882                         }
00883 
00884                         // Different revision types use different URL params...
00885                         $key = $params[3];
00886                         // This is a CSV of the IDs
00887                         $ids = explode( ',', $params[4] );
00888 
00889                         $links = array();
00890 
00891                         // If there's only one item, we can show a diff link
00892                         if ( count( $ids ) == 1 ) {
00893                                 // Live revision diffs...
00894                                 if ( $key == 'oldid' || $key == 'revision' ) {
00895                                         $links[] = Linker::linkKnown(
00896                                                 $this->entry->getTarget(),
00897                                                 $this->msg( 'diff' )->escaped(),
00898                                                 array(),
00899                                                 array(
00900                                                         'diff' => intval( $ids[0] ),
00901                                                         'unhide' => 1
00902                                                 )
00903                                         );
00904                                 // Deleted revision diffs...
00905                                 } elseif ( $key == 'artimestamp' || $key == 'archive' ) {
00906                                         $links[] = Linker::linkKnown(
00907                                                 SpecialPage::getTitleFor( 'Undelete' ),
00908                                                 $this->msg( 'diff' )->escaped(),
00909                                                 array(),
00910                                                 array(
00911                                                         'target'    => $this->entry->getTarget()->getPrefixedDBKey(),
00912                                                         'diff'      => 'prev',
00913                                                         'timestamp' => $ids[0]
00914                                                 )
00915                                         );
00916                                 }
00917                         }
00918 
00919                         // View/modify link...
00920                         $links[] = Linker::linkKnown(
00921                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00922                                 $this->msg( 'revdel-restore' )->escaped(),
00923                                 array(),
00924                                 array(
00925                                         'target' => $this->entry->getTarget()->getPrefixedText(),
00926                                         'type' => $key,
00927                                         'ids' => implode( ',', $ids ),
00928                                 )
00929                         );
00930 
00931                         return $this->msg( 'parentheses' )->rawParams(
00932                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00933 
00934                 case 'event': // Hidden log items, give review link
00935                         $params = $this->extractParameters();
00936                         if ( !isset( $params[3] ) ) {
00937                                 return '';
00938                         }
00939                         // This is a CSV of the IDs
00940                         $query = $params[3];
00941                         // Link to each hidden object ID, $params[1] is the url param
00942                         $revert = Linker::linkKnown(
00943                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00944                                 $this->msg( 'revdel-restore' )->escaped(),
00945                                 array(),
00946                                 array(
00947                                         'target' => $this->entry->getTarget()->getPrefixedText(),
00948                                         'type' => 'logging',
00949                                         'ids' => $query
00950                                 )
00951                         );
00952                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00953                 default:
00954                         return '';
00955                 }
00956         }
00957 }
00958 
00963 class PatrolLogFormatter extends LogFormatter {
00964         protected function getMessageKey() {
00965                 $key = parent::getMessageKey();
00966                 $params = $this->getMessageParameters();
00967                 if ( isset( $params[5] ) && $params[5] ) {
00968                         $key .= '-auto';
00969                 }
00970                 return $key;
00971         }
00972 
00973         protected function getMessageParameters() {
00974                 $params = parent::getMessageParameters();
00975 
00976                 $target = $this->entry->getTarget();
00977                 $oldid = $params[3];
00978                 $revision = $this->context->getLanguage()->formatNum( $oldid, true );
00979 
00980                 if ( $this->plaintext ) {
00981                         $revlink = $revision;
00982                 } elseif ( $target->exists() ) {
00983                         $query = array(
00984                                 'oldid' => $oldid,
00985                                 'diff' => 'prev'
00986                         );
00987                         $revlink = Linker::link( $target, htmlspecialchars( $revision ), array(), $query );
00988                 } else {
00989                         $revlink = htmlspecialchars( $revision );
00990                 }
00991 
00992                 $params[3] = Message::rawParam( $revlink );
00993                 return $params;
00994         }
00995 }
00996 
01001 class NewUsersLogFormatter extends LogFormatter {
01002         protected function getMessageParameters() {
01003                 $params = parent::getMessageParameters();
01004                 if ( $this->entry->getSubtype() === 'create2' ) {
01005                         if ( isset( $params[3] ) ) {
01006                                 $target = User::newFromId( $params[3] );
01007                         } else {
01008                                 $target = User::newFromName( $this->entry->getTarget()->getText(), false );
01009                         }
01010                         $params[2] = Message::rawParam( $this->makeUserLink( $target ) );
01011                         $params[3] = $target->getName();
01012                 }
01013                 return $params;
01014         }
01015 
01016         public function getComment() {
01017                 $timestamp = wfTimestamp( TS_MW, $this->entry->getTimestamp() );
01018                 if ( $timestamp < '20080129000000' ) {
01019                         # Suppress $comment from old entries (before 2008-01-29),
01020                         # not needed and can contain incorrect links
01021                         return '';
01022                 }
01023                 return parent::getComment();
01024         }
01025 
01026         public function getPreloadTitles() {
01027                 if ( $this->entry->getSubtype() === 'create2' ) {
01028                         //add the user talk to LinkBatch for the userLink
01029                         return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) );
01030                 }
01031                 return array();
01032         }
01033 }
01034 
01039 class RightsLogFormatter extends LogFormatter {
01040         protected function makePageLink( Title $title = null, $parameters = array() ) {
01041                 global $wgContLang, $wgUserrightsInterwikiDelimiter;
01042 
01043                 if ( !$this->plaintext ) {
01044                         $text = $wgContLang->ucfirst( $title->getText() );
01045                         $parts = explode( $wgUserrightsInterwikiDelimiter, $text, 2 );
01046 
01047                         if ( count( $parts ) === 2 ) {
01048                                 $titleLink = WikiMap::foreignUserLink( $parts[1], $parts[0],
01049                                         htmlspecialchars( $title->getPrefixedText() ) );
01050 
01051                                 if ( $titleLink !== false ) {
01052                                         return $titleLink;
01053                                 }
01054                         }
01055                 }
01056 
01057                 return parent::makePageLink( $title, $parameters );
01058         }
01059 
01060         protected function getMessageKey() {
01061                 $key = parent::getMessageKey();
01062                 $params = $this->getMessageParameters();
01063                 if ( !isset( $params[3] ) && !isset( $params[4] ) ) {
01064                         $key .= '-legacy';
01065                 }
01066                 return $key;
01067         }
01068 
01069         protected function getMessageParameters() {
01070                 $params = parent::getMessageParameters();
01071 
01072                 // Really old entries
01073                 if ( !isset( $params[3] ) && !isset( $params[4] ) ) {
01074                         return $params;
01075                 }
01076 
01077                 $oldGroups = $params[3];
01078                 $newGroups = $params[4];
01079 
01080                 // Less old entries
01081                 if ( $oldGroups === '' ) {
01082                         $oldGroups = array();
01083                 } elseif ( is_string( $oldGroups ) ) {
01084                         $oldGroups = array_map( 'trim', explode( ',', $oldGroups ) );
01085                 }
01086                 if ( $newGroups === '' ) {
01087                         $newGroups = array();
01088                 } elseif ( is_string( $newGroups ) ) {
01089                         $newGroups = array_map( 'trim', explode( ',', $newGroups ) );
01090                 }
01091 
01092                 $userName = $this->entry->getTarget()->getText();
01093                 if ( !$this->plaintext && count( $oldGroups ) ) {
01094                         foreach ( $oldGroups as &$group ) {
01095                                 $group = User::getGroupMember( $group, $userName );
01096                         }
01097                 }
01098                 if ( !$this->plaintext && count( $newGroups ) ) {
01099                         foreach ( $newGroups as &$group ) {
01100                                 $group = User::getGroupMember( $group, $userName );
01101                         }
01102                 }
01103 
01104                 $lang = $this->context->getLanguage();
01105                 if ( count( $oldGroups ) ) {
01106                         $params[3] = $lang->listToText( $oldGroups );
01107                 } else {
01108                         $params[3] = $this->msg( 'rightsnone' )->text();
01109                 }
01110                 if ( count( $newGroups ) ) {
01111                         $params[4] = $lang->listToText( $newGroups );
01112                 } else {
01113                         $params[4] = $this->msg( 'rightsnone' )->text();
01114                 }
01115 
01116                 return $params;
01117         }
01118 }