MediaWiki
REL1_21
|
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 case 'byemail': 00274 $text = wfMessage( 'newuserlog-create2-entry' ) 00275 ->rawParams( $target )->inContentLanguage()->escaped(); 00276 break; 00277 case 'autocreate': 00278 $text = wfMessage( 'newuserlog-autocreate-entry' ) 00279 ->inContentLanguage()->escaped(); 00280 break; 00281 } 00282 break; 00283 00284 case 'upload': 00285 switch( $entry->getSubtype() ) { 00286 case 'upload': 00287 $text = wfMessage( 'uploadedimage' ) 00288 ->rawParams( $target )->inContentLanguage()->escaped(); 00289 break; 00290 case 'overwrite': 00291 $text = wfMessage( 'overwroteimage' ) 00292 ->rawParams( $target )->inContentLanguage()->escaped(); 00293 break; 00294 } 00295 break; 00296 00297 case 'rights': 00298 if ( count( $parameters['4::oldgroups'] ) ) { 00299 $oldgroups = implode( ', ', $parameters['4::oldgroups'] ); 00300 } else { 00301 $oldgroups = wfMessage( 'rightsnone' )->inContentLanguage()->escaped(); 00302 } 00303 if ( count( $parameters['5::newgroups'] ) ) { 00304 $newgroups = implode( ', ', $parameters['5::newgroups'] ); 00305 } else { 00306 $newgroups = wfMessage( 'rightsnone' )->inContentLanguage()->escaped(); 00307 } 00308 switch( $entry->getSubtype() ) { 00309 case 'rights': 00310 $text = wfMessage( 'rightslogentry' ) 00311 ->rawParams( $target, $oldgroups, $newgroups )->inContentLanguage()->escaped(); 00312 break; 00313 case 'autopromote': 00314 $text = wfMessage( 'rightslogentry-autopromote' ) 00315 ->rawParams( $target, $oldgroups, $newgroups )->inContentLanguage()->escaped(); 00316 break; 00317 } 00318 break; 00319 00320 // case 'suppress' --private log -- aaron (sign your messages so we know who to blame in a few years :-D) 00321 // default: 00322 } 00323 if( is_null( $text ) ) { 00324 $text = $this->getPlainActionText(); 00325 } 00326 00327 $this->plaintext = false; 00328 $this->irctext = false; 00329 return $text; 00330 } 00331 00336 public function getActionText() { 00337 if ( $this->canView( LogPage::DELETED_ACTION ) ) { 00338 $element = $this->getActionMessage(); 00339 if ( $element instanceof Message ) { 00340 $element = $this->plaintext ? $element->text() : $element->escaped(); 00341 } 00342 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { 00343 $element = $this->styleRestricedElement( $element ); 00344 } 00345 } else { 00346 $performer = $this->getPerformerElement() . $this->msg( 'word-separator' )->text(); 00347 $element = $performer . $this->getRestrictedElement( 'rev-deleted-event' ); 00348 } 00349 00350 return $element; 00351 } 00352 00359 protected function getActionMessage() { 00360 $message = $this->msg( $this->getMessageKey() ); 00361 $message->params( $this->getMessageParameters() ); 00362 return $message; 00363 } 00364 00372 protected function getMessageKey() { 00373 $type = $this->entry->getType(); 00374 $subtype = $this->entry->getSubtype(); 00375 00376 return "logentry-$type-$subtype"; 00377 } 00378 00384 public function getActionLinks() { 00385 return ''; 00386 } 00387 00393 protected function extractParameters() { 00394 $entry = $this->entry; 00395 $params = array(); 00396 00397 if ( $entry->isLegacy() ) { 00398 foreach ( $entry->getParameters() as $index => $value ) { 00399 $params[$index + 3] = $value; 00400 } 00401 } 00402 00403 // Filter out parameters which are not in format #:foo 00404 foreach ( $entry->getParameters() as $key => $value ) { 00405 if ( strpos( $key, ':' ) === false ) { 00406 continue; 00407 } 00408 list( $index, $type, ) = explode( ':', $key, 3 ); 00409 $params[$index - 1] = $this->formatParameterValue( $type, $value ); 00410 } 00411 00412 /* Message class doesn't like non consecutive numbering. 00413 * Fill in missing indexes with empty strings to avoid 00414 * incorrect renumbering. 00415 */ 00416 if ( count( $params ) ) { 00417 $max = max( array_keys( $params ) ); 00418 for ( $i = 4; $i < $max; $i++ ) { 00419 if ( !isset( $params[$i] ) ) { 00420 $params[$i] = ''; 00421 } 00422 } 00423 } 00424 return $params; 00425 } 00426 00436 protected function getMessageParameters() { 00437 if ( isset( $this->parsedParameters ) ) { 00438 return $this->parsedParameters; 00439 } 00440 00441 $entry = $this->entry; 00442 $params = $this->extractParameters(); 00443 $params[0] = Message::rawParam( $this->getPerformerElement() ); 00444 $params[1] = $this->canView( LogPage::DELETED_USER ) ? $entry->getPerformer()->getName() : ''; 00445 $params[2] = Message::rawParam( $this->makePageLink( $entry->getTarget() ) ); 00446 00447 // Bad things happens if the numbers are not in correct order 00448 ksort( $params ); 00449 return $this->parsedParameters = $params; 00450 } 00451 00479 protected function formatParameterValue( $type, $value ) { 00480 $saveLinkFlood = $this->linkFlood; 00481 00482 switch( strtolower( trim( $type ) ) ) { 00483 case 'raw': 00484 $value = Message::rawParam( $value ); 00485 break; 00486 case 'msg': 00487 $value = $this->msg( $value )->text(); 00488 break; 00489 case 'msg-content': 00490 $value = $this->msg( $value )->inContentLanguage()->text(); 00491 break; 00492 case 'number': 00493 $value = Message::numParam( $value ); 00494 break; 00495 case 'user': 00496 $user = User::newFromName( $value ); 00497 $value = $user->getName(); 00498 break; 00499 case 'user-link': 00500 $this->setShowUserToolLinks( false ); 00501 00502 $user = User::newFromName( $value ); 00503 $value = Message::rawParam( $this->makeUserLink( $user ) ); 00504 00505 $this->setShowUserToolLinks( $saveLinkFlood ); 00506 break; 00507 case 'title': 00508 $title = Title::newFromText( $value ); 00509 $value = $title->getPrefixedText(); 00510 break; 00511 case 'title-link': 00512 $title = Title::newFromText( $value ); 00513 $value = Message::rawParam( $this->makePageLink( $title ) ); 00514 break; 00515 case 'plain': 00516 // Plain text, nothing to do 00517 default: 00518 // Catch other types and use the old behavior (return as-is) 00519 } 00520 00521 return $value; 00522 } 00523 00532 protected function makePageLink( Title $title = null, $parameters = array() ) { 00533 if ( !$this->plaintext ) { 00534 $link = Linker::link( $title, null, array(), $parameters ); 00535 } else { 00536 if ( !$title instanceof Title ) { 00537 throw new MWException( "Expected title, got null" ); 00538 } 00539 $link = '[[' . $title->getPrefixedText() . ']]'; 00540 } 00541 return $link; 00542 } 00543 00550 public function getPerformerElement() { 00551 if ( $this->canView( LogPage::DELETED_USER ) ) { 00552 $performer = $this->entry->getPerformer(); 00553 $element = $this->makeUserLink( $performer ); 00554 if ( $this->entry->isDeleted( LogPage::DELETED_USER ) ) { 00555 $element = $this->styleRestricedElement( $element ); 00556 } 00557 } else { 00558 $element = $this->getRestrictedElement( 'rev-deleted-user' ); 00559 } 00560 00561 return $element; 00562 } 00563 00568 public function getComment() { 00569 if ( $this->canView( LogPage::DELETED_COMMENT ) ) { 00570 $comment = Linker::commentBlock( $this->entry->getComment() ); 00571 // No hard coded spaces thanx 00572 $element = ltrim( $comment ); 00573 if ( $this->entry->isDeleted( LogPage::DELETED_COMMENT ) ) { 00574 $element = $this->styleRestricedElement( $element ); 00575 } 00576 } else { 00577 $element = $this->getRestrictedElement( 'rev-deleted-comment' ); 00578 } 00579 00580 return $element; 00581 } 00582 00588 protected function getRestrictedElement( $message ) { 00589 if ( $this->plaintext ) { 00590 return $this->msg( $message )->text(); 00591 } 00592 00593 $content = $this->msg( $message )->escaped(); 00594 $attribs = array( 'class' => 'history-deleted' ); 00595 return Html::rawElement( 'span', $attribs, $content ); 00596 } 00597 00603 protected function styleRestricedElement( $content ) { 00604 if ( $this->plaintext ) { 00605 return $content; 00606 } 00607 $attribs = array( 'class' => 'history-deleted' ); 00608 return Html::rawElement( 'span', $attribs, $content ); 00609 } 00610 00617 protected function msg( $key ) { 00618 return $this->context->msg( $key ); 00619 } 00620 00621 protected function makeUserLink( User $user ) { 00622 if ( $this->plaintext ) { 00623 $element = $user->getName(); 00624 } else { 00625 $element = Linker::userLink( 00626 $user->getId(), 00627 $user->getName() 00628 ); 00629 00630 if ( $this->linkFlood ) { 00631 $element .= Linker::userToolLinksRedContribs( 00632 $user->getId(), 00633 $user->getName(), 00634 $user->getEditCount() 00635 ); 00636 } 00637 } 00638 return $element; 00639 } 00640 00644 public function getPreloadTitles() { 00645 return array(); 00646 } 00647 00651 public function getMessageParametersForTesting() { 00652 // This function was added because getMessageParameters() is 00653 // protected and a change from protected to public caused 00654 // problems with extensions 00655 return $this->getMessageParameters(); 00656 } 00657 00658 } 00659 00669 class LegacyLogFormatter extends LogFormatter { 00670 00680 private $comment = null; 00681 00689 private $revert = null; 00690 00691 public function getComment() { 00692 if ( $this->comment === null ) { 00693 $this->comment = parent::getComment(); 00694 } 00695 00696 // Make sure we execute the LogLine hook so that we immediately return 00697 // the correct value. 00698 if ( $this->revert === null ) { 00699 $this->getActionLinks(); 00700 } 00701 00702 return $this->comment; 00703 } 00704 00705 protected function getActionMessage() { 00706 $entry = $this->entry; 00707 $action = LogPage::actionText( 00708 $entry->getType(), 00709 $entry->getSubtype(), 00710 $entry->getTarget(), 00711 $this->plaintext ? null : $this->context->getSkin(), 00712 (array)$entry->getParameters(), 00713 !$this->plaintext // whether to filter [[]] links 00714 ); 00715 00716 $performer = $this->getPerformerElement(); 00717 if ( !$this->irctext ) { 00718 $action = $performer . $this->msg( 'word-separator' )->text() . $action; 00719 } 00720 00721 return $action; 00722 } 00723 00724 public function getActionLinks() { 00725 if ( $this->revert !== null ) { 00726 return $this->revert; 00727 } 00728 00729 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { 00730 return $this->revert = ''; 00731 } 00732 00733 $title = $this->entry->getTarget(); 00734 $type = $this->entry->getType(); 00735 $subtype = $this->entry->getSubtype(); 00736 00737 // Show unblock/change block link 00738 if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) { 00739 if ( !$this->context->getUser()->isAllowed( 'block' ) ) { 00740 return ''; 00741 } 00742 00743 $links = array( 00744 Linker::linkKnown( 00745 SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ), 00746 $this->msg( 'unblocklink' )->escaped() 00747 ), 00748 Linker::linkKnown( 00749 SpecialPage::getTitleFor( 'Block', $title->getDBkey() ), 00750 $this->msg( 'change-blocklink' )->escaped() 00751 ) 00752 ); 00753 return $this->msg( 'parentheses' )->rawParams( 00754 $this->context->getLanguage()->pipeList( $links ) )->escaped(); 00755 // Show change protection link 00756 } elseif ( $type == 'protect' && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) ) { 00757 $links = array( 00758 Linker::link( $title, 00759 $this->msg( 'hist' )->escaped(), 00760 array(), 00761 array( 00762 'action' => 'history', 00763 'offset' => $this->entry->getTimestamp() 00764 ) 00765 ) 00766 ); 00767 if ( $this->context->getUser()->isAllowed( 'protect' ) ) { 00768 $links[] = Linker::linkKnown( 00769 $title, 00770 $this->msg( 'protect_change' )->escaped(), 00771 array(), 00772 array( 'action' => 'protect' ) 00773 ); 00774 } 00775 return $this->msg( 'parentheses' )->rawParams( 00776 $this->context->getLanguage()->pipeList( $links ) )->escaped(); 00777 // Show unmerge link 00778 } elseif( $type == 'merge' && $subtype == 'merge' ) { 00779 if ( !$this->context->getUser()->isAllowed( 'mergehistory' ) ) { 00780 return ''; 00781 } 00782 00783 $params = $this->extractParameters(); 00784 $revert = Linker::linkKnown( 00785 SpecialPage::getTitleFor( 'MergeHistory' ), 00786 $this->msg( 'revertmerge' )->escaped(), 00787 array(), 00788 array( 00789 'target' => $params[3], 00790 'dest' => $title->getPrefixedDBkey(), 00791 'mergepoint' => $params[4] 00792 ) 00793 ); 00794 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); 00795 } 00796 00797 // Do nothing. The implementation is handled by the hook modifiying the 00798 // passed-by-ref parameters. This also changes the default value so that 00799 // getComment() and getActionLinks() do not call them indefinitely. 00800 $this->revert = ''; 00801 00802 // This is to populate the $comment member of this instance so that it 00803 // can be modified when calling the hook just below. 00804 if ( $this->comment === null ) { 00805 $this->getComment(); 00806 } 00807 00808 $params = $this->entry->getParameters(); 00809 00810 wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params, 00811 &$this->comment, &$this->revert, $this->entry->getTimestamp() ) ); 00812 00813 return $this->revert; 00814 } 00815 } 00816 00821 class MoveLogFormatter extends LogFormatter { 00822 public function getPreloadTitles() { 00823 $params = $this->extractParameters(); 00824 return array( Title::newFromText( $params[3] ) ); 00825 } 00826 00827 protected function getMessageKey() { 00828 $key = parent::getMessageKey(); 00829 $params = $this->getMessageParameters(); 00830 if ( isset( $params[4] ) && $params[4] === '1' ) { 00831 $key .= '-noredirect'; 00832 } 00833 return $key; 00834 } 00835 00836 protected function getMessageParameters() { 00837 $params = parent::getMessageParameters(); 00838 $oldname = $this->makePageLink( $this->entry->getTarget(), array( 'redirect' => 'no' ) ); 00839 $newname = $this->makePageLink( Title::newFromText( $params[3] ) ); 00840 $params[2] = Message::rawParam( $oldname ); 00841 $params[3] = Message::rawParam( $newname ); 00842 return $params; 00843 } 00844 00845 public function getActionLinks() { 00846 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden 00847 || $this->entry->getSubtype() !== 'move' 00848 || !$this->context->getUser()->isAllowed( 'move' ) ) 00849 { 00850 return ''; 00851 } 00852 00853 $params = $this->extractParameters(); 00854 $destTitle = Title::newFromText( $params[3] ); 00855 if ( !$destTitle ) { 00856 return ''; 00857 } 00858 00859 $revert = Linker::linkKnown( 00860 SpecialPage::getTitleFor( 'Movepage' ), 00861 $this->msg( 'revertmove' )->escaped(), 00862 array(), 00863 array( 00864 'wpOldTitle' => $destTitle->getPrefixedDBkey(), 00865 'wpNewTitle' => $this->entry->getTarget()->getPrefixedDBkey(), 00866 'wpReason' => $this->msg( 'revertmove' )->inContentLanguage()->text(), 00867 'wpMovetalk' => 0 00868 ) 00869 ); 00870 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); 00871 } 00872 } 00873 00878 class DeleteLogFormatter extends LogFormatter { 00879 protected function getMessageKey() { 00880 $key = parent::getMessageKey(); 00881 if ( in_array( $this->entry->getSubtype(), array( 'event', 'revision' ) ) ) { 00882 if ( count( $this->getMessageParameters() ) < 5 ) { 00883 return "$key-legacy"; 00884 } 00885 } 00886 return $key; 00887 } 00888 00889 protected function getMessageParameters() { 00890 if ( isset( $this->parsedParametersDeleteLog ) ) { 00891 return $this->parsedParametersDeleteLog; 00892 } 00893 00894 $params = parent::getMessageParameters(); 00895 $subtype = $this->entry->getSubtype(); 00896 if ( in_array( $subtype, array( 'event', 'revision' ) ) ) { 00897 // $params[3] here is 'revision' for page revisions, 'oldimage' for file versions, or a comma-separated list of log_ids for log entries. 00898 // $subtype here is 'revision' for page revisions and file versions, or 'event' for log entries. 00899 if ( 00900 ( $subtype === 'event' && count( $params ) === 6 ) || 00901 ( $subtype === 'revision' && isset( $params[3] ) && ( $params[3] === 'revision' || $params[3] === 'oldimage' ) ) 00902 ) { 00903 $paramStart = $subtype === 'revision' ? 4 : 3; 00904 00905 $old = $this->parseBitField( $params[$paramStart+1] ); 00906 $new = $this->parseBitField( $params[$paramStart+2] ); 00907 list( $hid, $unhid, $extra ) = RevisionDeleter::getChanges( $new, $old ); 00908 $changes = array(); 00909 foreach ( $hid as $v ) { 00910 $changes[] = $this->msg( "$v-hid" )->plain(); 00911 } 00912 foreach ( $unhid as $v ) { 00913 $changes[] = $this->msg( "$v-unhid" )->plain(); 00914 } 00915 foreach ( $extra as $v ) { 00916 $changes[] = $this->msg( $v )->plain(); 00917 } 00918 $changeText = $this->context->getLanguage()->listToText( $changes ); 00919 00920 $newParams = array_slice( $params, 0, 3 ); 00921 $newParams[3] = $changeText; 00922 $count = count( explode( ',', $params[$paramStart] ) ); 00923 $newParams[4] = $this->context->getLanguage()->formatNum( $count ); 00924 return $this->parsedParametersDeleteLog = $newParams; 00925 } else { 00926 return $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 ); 00927 } 00928 } 00929 00930 return $this->parsedParametersDeleteLog = $params; 00931 } 00932 00933 protected function parseBitField( $string ) { 00934 // Input is like ofield=2134 or just the number 00935 if ( strpos( $string, 'field=' ) === 1 ) { 00936 list( , $field ) = explode( '=', $string ); 00937 return (int) $field; 00938 } else { 00939 return (int) $string; 00940 } 00941 } 00942 00943 public function getActionLinks() { 00944 $user = $this->context->getUser(); 00945 if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { 00946 return ''; 00947 } 00948 00949 switch ( $this->entry->getSubtype() ) { 00950 case 'delete': // Show undelete link 00951 if( $user->isAllowed( 'undelete' ) ) { 00952 $message = 'undeletelink'; 00953 } else { 00954 $message = 'undeleteviewlink'; 00955 } 00956 $revert = Linker::linkKnown( 00957 SpecialPage::getTitleFor( 'Undelete' ), 00958 $this->msg( $message )->escaped(), 00959 array(), 00960 array( 'target' => $this->entry->getTarget()->getPrefixedDBkey() ) 00961 ); 00962 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); 00963 00964 case 'revision': // If an edit was hidden from a page give a review link to the history 00965 $params = $this->extractParameters(); 00966 if ( !isset( $params[3] ) || !isset( $params[4] ) ) { 00967 return ''; 00968 } 00969 00970 // Different revision types use different URL params... 00971 $key = $params[3]; 00972 // This is a CSV of the IDs 00973 $ids = explode( ',', $params[4] ); 00974 00975 $links = array(); 00976 00977 // If there's only one item, we can show a diff link 00978 if ( count( $ids ) == 1 ) { 00979 // Live revision diffs... 00980 if ( $key == 'oldid' || $key == 'revision' ) { 00981 $links[] = Linker::linkKnown( 00982 $this->entry->getTarget(), 00983 $this->msg( 'diff' )->escaped(), 00984 array(), 00985 array( 00986 'diff' => intval( $ids[0] ), 00987 'unhide' => 1 00988 ) 00989 ); 00990 // Deleted revision diffs... 00991 } elseif ( $key == 'artimestamp' || $key == 'archive' ) { 00992 $links[] = Linker::linkKnown( 00993 SpecialPage::getTitleFor( 'Undelete' ), 00994 $this->msg( 'diff' )->escaped(), 00995 array(), 00996 array( 00997 'target' => $this->entry->getTarget()->getPrefixedDBkey(), 00998 'diff' => 'prev', 00999 'timestamp' => $ids[0] 01000 ) 01001 ); 01002 } 01003 } 01004 01005 // View/modify link... 01006 $links[] = Linker::linkKnown( 01007 SpecialPage::getTitleFor( 'Revisiondelete' ), 01008 $this->msg( 'revdel-restore' )->escaped(), 01009 array(), 01010 array( 01011 'target' => $this->entry->getTarget()->getPrefixedText(), 01012 'type' => $key, 01013 'ids' => implode( ',', $ids ), 01014 ) 01015 ); 01016 01017 return $this->msg( 'parentheses' )->rawParams( 01018 $this->context->getLanguage()->pipeList( $links ) )->escaped(); 01019 01020 case 'event': // Hidden log items, give review link 01021 $params = $this->extractParameters(); 01022 if ( !isset( $params[3] ) ) { 01023 return ''; 01024 } 01025 // This is a CSV of the IDs 01026 $query = $params[3]; 01027 // Link to each hidden object ID, $params[1] is the url param 01028 $revert = Linker::linkKnown( 01029 SpecialPage::getTitleFor( 'Revisiondelete' ), 01030 $this->msg( 'revdel-restore' )->escaped(), 01031 array(), 01032 array( 01033 'target' => $this->entry->getTarget()->getPrefixedText(), 01034 'type' => 'logging', 01035 'ids' => $query 01036 ) 01037 ); 01038 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); 01039 default: 01040 return ''; 01041 } 01042 } 01043 } 01044 01049 class PatrolLogFormatter extends LogFormatter { 01050 protected function getMessageKey() { 01051 $key = parent::getMessageKey(); 01052 $params = $this->getMessageParameters(); 01053 if ( isset( $params[5] ) && $params[5] ) { 01054 $key .= '-auto'; 01055 } 01056 return $key; 01057 } 01058 01059 protected function getMessageParameters() { 01060 $params = parent::getMessageParameters(); 01061 01062 $target = $this->entry->getTarget(); 01063 $oldid = $params[3]; 01064 $revision = $this->context->getLanguage()->formatNum( $oldid, true ); 01065 01066 if ( $this->plaintext ) { 01067 $revlink = $revision; 01068 } elseif ( $target->exists() ) { 01069 $query = array( 01070 'oldid' => $oldid, 01071 'diff' => 'prev' 01072 ); 01073 $revlink = Linker::link( $target, htmlspecialchars( $revision ), array(), $query ); 01074 } else { 01075 $revlink = htmlspecialchars( $revision ); 01076 } 01077 01078 $params[3] = Message::rawParam( $revlink ); 01079 return $params; 01080 } 01081 } 01082 01087 class NewUsersLogFormatter extends LogFormatter { 01088 protected function getMessageParameters() { 01089 $params = parent::getMessageParameters(); 01090 $subtype = $this->entry->getSubtype(); 01091 if ( $subtype === 'create2' || $subtype === 'byemail' ) { 01092 if ( isset( $params[3] ) ) { 01093 $target = User::newFromId( $params[3] ); 01094 } else { 01095 $target = User::newFromName( $this->entry->getTarget()->getText(), false ); 01096 } 01097 $params[2] = Message::rawParam( $this->makeUserLink( $target ) ); 01098 $params[3] = $target->getName(); 01099 } 01100 return $params; 01101 } 01102 01103 public function getComment() { 01104 $timestamp = wfTimestamp( TS_MW, $this->entry->getTimestamp() ); 01105 if ( $timestamp < '20080129000000' ) { 01106 # Suppress $comment from old entries (before 2008-01-29), 01107 # not needed and can contain incorrect links 01108 return ''; 01109 } 01110 return parent::getComment(); 01111 } 01112 01113 public function getPreloadTitles() { 01114 $subtype = $this->entry->getSubtype(); 01115 if ( $subtype === 'create2' || $subtype === 'byemail' ) { 01116 //add the user talk to LinkBatch for the userLink 01117 return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) ); 01118 } 01119 return array(); 01120 } 01121 } 01122 01127 class RightsLogFormatter extends LogFormatter { 01128 protected function makePageLink( Title $title = null, $parameters = array() ) { 01129 global $wgContLang, $wgUserrightsInterwikiDelimiter; 01130 01131 if ( !$this->plaintext ) { 01132 $text = $wgContLang->ucfirst( $title->getText() ); 01133 $parts = explode( $wgUserrightsInterwikiDelimiter, $text, 2 ); 01134 01135 if ( count( $parts ) === 2 ) { 01136 $titleLink = WikiMap::foreignUserLink( $parts[1], $parts[0], 01137 htmlspecialchars( $title->getPrefixedText() ) ); 01138 01139 if ( $titleLink !== false ) { 01140 return $titleLink; 01141 } 01142 } 01143 } 01144 01145 return parent::makePageLink( $title, $parameters ); 01146 } 01147 01148 protected function getMessageKey() { 01149 $key = parent::getMessageKey(); 01150 $params = $this->getMessageParameters(); 01151 if ( !isset( $params[3] ) && !isset( $params[4] ) ) { 01152 $key .= '-legacy'; 01153 } 01154 return $key; 01155 } 01156 01157 protected function getMessageParameters() { 01158 $params = parent::getMessageParameters(); 01159 01160 // Really old entries 01161 if ( !isset( $params[3] ) && !isset( $params[4] ) ) { 01162 return $params; 01163 } 01164 01165 $oldGroups = $params[3]; 01166 $newGroups = $params[4]; 01167 01168 // Less old entries 01169 if ( $oldGroups === '' ) { 01170 $oldGroups = array(); 01171 } elseif ( is_string( $oldGroups ) ) { 01172 $oldGroups = array_map( 'trim', explode( ',', $oldGroups ) ); 01173 } 01174 if ( $newGroups === '' ) { 01175 $newGroups = array(); 01176 } elseif ( is_string( $newGroups ) ) { 01177 $newGroups = array_map( 'trim', explode( ',', $newGroups ) ); 01178 } 01179 01180 $userName = $this->entry->getTarget()->getText(); 01181 if ( !$this->plaintext && count( $oldGroups ) ) { 01182 foreach ( $oldGroups as &$group ) { 01183 $group = User::getGroupMember( $group, $userName ); 01184 } 01185 } 01186 if ( !$this->plaintext && count( $newGroups ) ) { 01187 foreach ( $newGroups as &$group ) { 01188 $group = User::getGroupMember( $group, $userName ); 01189 } 01190 } 01191 01192 $lang = $this->context->getLanguage(); 01193 if ( count( $oldGroups ) ) { 01194 $params[3] = $lang->listToText( $oldGroups ); 01195 } else { 01196 $params[3] = $this->msg( 'rightsnone' )->text(); 01197 } 01198 if ( count( $newGroups ) ) { 01199 // Array_values is used here because of bug 42211 01200 // see use of array_unique in UserrightsPage::doSaveUserGroups on $newGroups. 01201 $params[4] = $lang->listToText( array_values( $newGroups ) ); 01202 } else { 01203 $params[4] = $this->msg( 'rightsnone' )->text(); 01204 } 01205 01206 return $params; 01207 } 01208 }