MediaWiki
master
|
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 }