MediaWiki
REL1_19
|
00001 <?php 00018 class LogFormatter { 00019 // Audience options for viewing usernames, comments, and actions 00020 const FOR_PUBLIC = 1; 00021 const FOR_THIS_USER = 2; 00022 00023 // Static-> 00024 00030 public static function newFromEntry( LogEntry $entry ) { 00031 global $wgLogActionsHandlers; 00032 $fulltype = $entry->getFullType(); 00033 $wildcard = $entry->getType() . '/*'; 00034 $handler = ''; 00035 00036 if ( isset( $wgLogActionsHandlers[$fulltype] ) ) { 00037 $handler = $wgLogActionsHandlers[$fulltype]; 00038 } elseif ( isset( $wgLogActionsHandlers[$wildcard] ) ) { 00039 $handler = $wgLogActionsHandlers[$wildcard]; 00040 } 00041 00042 if ( $handler !== '' && is_string( $handler ) && class_exists( $handler ) ) { 00043 return new $handler( $entry ); 00044 } 00045 00046 return new LegacyLogFormatter( $entry ); 00047 } 00048 00056 public static function newFromRow( $row ) { 00057 return self::newFromEntry( DatabaseLogEntry::newFromRow( $row ) ); 00058 } 00059 00060 // Nonstatic-> 00061 00063 protected $entry; 00064 00066 protected $audience = self::FOR_PUBLIC; 00067 00069 protected $linkFlood = false; 00070 00078 protected $plaintext = false; 00079 00080 protected $irctext = false; 00081 00082 protected function __construct( LogEntry $entry ) { 00083 $this->entry = $entry; 00084 $this->context = RequestContext::getMain(); 00085 } 00086 00091 public function setContext( IContextSource $context ) { 00092 $this->context = $context; 00093 } 00094 00101 public function setAudience( $audience ) { 00102 $this->audience = ( $audience == self::FOR_THIS_USER ) 00103 ? self::FOR_THIS_USER 00104 : self::FOR_PUBLIC; 00105 } 00106 00112 protected function canView( $field ) { 00113 if ( $this->audience == self::FOR_THIS_USER ) { 00114 return LogEventsList::userCanBitfield( 00115 $this->entry->getDeleted(), $field, $this->context->getUser() ); 00116 } else { 00117 return !$this->entry->isDeleted( $field ); 00118 } 00119 } 00120 00127 public function setShowUserToolLinks( $value ) { 00128 $this->linkFlood = $value; 00129 } 00130 00138 public function getPlainActionText() { 00139 $this->plaintext = true; 00140 $text = $this->getActionText(); 00141 $this->plaintext = false; 00142 return $text; 00143 } 00144 00151 public function getIRCActionText() { 00152 $this->plaintext = true; 00153 $text = $this->getActionText(); 00154 00155 $entry = $this->entry; 00156 $parameters = $entry->getParameters(); 00157 // @see LogPage::actionText() 00158 $msgOpts = array( 'parsemag', 'escape', 'replaceafter', 'content' ); 00159 // Text of title the action is aimed at. 00160 $target = $entry->getTarget()->getPrefixedText() ; 00161 $text = null; 00162 switch( $entry->getType() ) { 00163 case 'move': 00164 switch( $entry->getSubtype() ) { 00165 case 'move': 00166 $movesource = $parameters['4::target']; 00167 $text = wfMsgExt( '1movedto2', $msgOpts, $target, $movesource ); 00168 break; 00169 case 'move_redir': 00170 $movesource = $parameters['4::target']; 00171 $text = wfMsgExt( '1movedto2_redir', $msgOpts, $target, $movesource ); 00172 break; 00173 case 'move-noredirect': 00174 break; 00175 case 'move_redir-noredirect': 00176 break; 00177 } 00178 break; 00179 00180 case 'delete': 00181 switch( $entry->getSubtype() ) { 00182 case 'delete': 00183 $text = wfMsgExt( 'deletedarticle', $msgOpts, $target ); 00184 break; 00185 case 'restore': 00186 $text = wfMsgExt( 'undeletedarticle', $msgOpts, $target ); 00187 break; 00188 //case 'revision': // Revision deletion 00189 //case 'event': // Log deletion 00190 // see https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/LogPage.php?&pathrev=97044&r1=97043&r2=97044 00191 //default: 00192 } 00193 break; 00194 00195 case 'patrol': 00196 // https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/PatrolLog.php?&pathrev=97495&r1=97494&r2=97495 00197 // Create a diff link to the patrolled revision 00198 if ( $entry->getSubtype() === 'patrol' ) { 00199 $diffLink = htmlspecialchars( 00200 wfMsgForContent( 'patrol-log-diff', $parameters['4::curid'] ) ); 00201 $text = wfMsgForContent( 'patrol-log-line', $diffLink, "[[$target]]", "" ); 00202 } else { 00203 // broken?? 00204 } 00205 break; 00206 00207 case 'newusers': 00208 switch( $entry->getSubtype() ) { 00209 case 'newusers': 00210 case 'create': 00211 $text = wfMsgExt( 'newuserlog-create-entry', $msgOpts /* no params */ ); 00212 break; 00213 case 'create2': 00214 $text = wfMsgExt( 'newuserlog-create2-entry', $msgOpts, $target ); 00215 break; 00216 case 'autocreate': 00217 $text = wfMsgExt( 'newuserlog-autocreate-entry', $msgOpts /* no params */ ); 00218 break; 00219 } 00220 break; 00221 00222 case 'upload': 00223 switch( $entry->getSubtype() ) { 00224 case 'upload': 00225 $text = wfMsgExt( 'uploadedimage', $msgOpts, $target ); 00226 break; 00227 case 'overwrite': 00228 $text = wfMsgExt( 'overwroteimage', $msgOpts, $target ); 00229 break; 00230 } 00231 break; 00232 00233 // case 'suppress' --private log -- aaron (sign your messages so we know who to blame in a few years :-D) 00234 // default: 00235 } 00236 if( is_null( $text ) ) { 00237 $text = $this->getPlainActionText(); 00238 } 00239 00240 $this->plaintext = false; 00241 return $text; 00242 } 00243 00248 public function getActionText() { 00249 if ( $this->canView( LogPage::DELETED_ACTION ) ) { 00250 $element = $this->getActionMessage(); 00251 if ( $element instanceof Message ) { 00252 $element = $this->plaintext ? $element->text() : $element->escaped(); 00253 } 00254 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { 00255 $element = $this->styleRestricedElement( $element ); 00256 } 00257 } else { 00258 $performer = $this->getPerformerElement() . $this->msg( 'word-separator' )->text(); 00259 $element = $performer . $this->getRestrictedElement( 'rev-deleted-event' ); 00260 } 00261 00262 return $element; 00263 } 00264 00271 protected function getActionMessage() { 00272 $message = $this->msg( $this->getMessageKey() ); 00273 $message->params( $this->getMessageParameters() ); 00274 return $message; 00275 } 00276 00284 protected function getMessageKey() { 00285 $type = $this->entry->getType(); 00286 $subtype = $this->entry->getSubtype(); 00287 00288 return "logentry-$type-$subtype"; 00289 } 00290 00296 protected function extractParameters() { 00297 $entry = $this->entry; 00298 $params = array(); 00299 00300 if ( $entry->isLegacy() ) { 00301 foreach ( $entry->getParameters() as $index => $value ) { 00302 $params[$index + 3] = $value; 00303 } 00304 } 00305 00306 // Filter out parameters which are not in format #:foo 00307 foreach ( $entry->getParameters() as $key => $value ) { 00308 if ( strpos( $key, ':' ) === false ) continue; 00309 list( $index, $type, $name ) = explode( ':', $key, 3 ); 00310 $params[$index - 1] = $value; 00311 } 00312 00313 /* Message class doesn't like non consecutive numbering. 00314 * Fill in missing indexes with empty strings to avoid 00315 * incorrect renumbering. 00316 */ 00317 if ( count( $params ) ) { 00318 $max = max( array_keys( $params ) ); 00319 for ( $i = 4; $i < $max; $i++ ) { 00320 if ( !isset( $params[$i] ) ) { 00321 $params[$i] = ''; 00322 } 00323 } 00324 } 00325 return $params; 00326 } 00327 00337 protected function getMessageParameters() { 00338 if ( isset( $this->parsedParameters ) ) { 00339 return $this->parsedParameters; 00340 } 00341 00342 $entry = $this->entry; 00343 $params = $this->extractParameters(); 00344 $params[0] = Message::rawParam( $this->getPerformerElement() ); 00345 $params[1] = $entry->getPerformer()->getName(); 00346 $params[2] = Message::rawParam( $this->makePageLink( $entry->getTarget() ) ); 00347 00348 // Bad things happens if the numbers are not in correct order 00349 ksort( $params ); 00350 return $this->parsedParameters = $params; 00351 } 00352 00360 protected function makePageLink( Title $title = null, $parameters = array() ) { 00361 if ( !$this->plaintext ) { 00362 $link = Linker::link( $title, null, array(), $parameters ); 00363 } else { 00364 if ( !$title instanceof Title ) { 00365 throw new MWException( "Expected title, got null" ); 00366 } 00367 $link = '[[' . $title->getPrefixedText() . ']]'; 00368 } 00369 return $link; 00370 } 00371 00377 public function getPerformerElement() { 00378 if ( $this->canView( LogPage::DELETED_USER ) ) { 00379 $performer = $this->entry->getPerformer(); 00380 $element = $this->makeUserLink( $performer ); 00381 if ( $this->entry->isDeleted( LogPage::DELETED_USER ) ) { 00382 $element = $this->styleRestricedElement( $element ); 00383 } 00384 } else { 00385 $element = $this->getRestrictedElement( 'rev-deleted-user' ); 00386 } 00387 00388 return $element; 00389 } 00390 00395 public function getComment() { 00396 if ( $this->canView( LogPage::DELETED_COMMENT ) ) { 00397 $comment = Linker::commentBlock( $this->entry->getComment() ); 00398 // No hard coded spaces thanx 00399 $element = ltrim( $comment ); 00400 if ( $this->entry->isDeleted( LogPage::DELETED_COMMENT ) ) { 00401 $element = $this->styleRestricedElement( $element ); 00402 } 00403 } else { 00404 $element = $this->getRestrictedElement( 'rev-deleted-comment' ); 00405 } 00406 00407 return $element; 00408 } 00409 00415 protected function getRestrictedElement( $message ) { 00416 if ( $this->plaintext ) { 00417 return $this->msg( $message )->text(); 00418 } 00419 00420 $content = $this->msg( $message )->escaped(); 00421 $attribs = array( 'class' => 'history-deleted' ); 00422 return Html::rawElement( 'span', $attribs, $content ); 00423 } 00424 00430 protected function styleRestricedElement( $content ) { 00431 if ( $this->plaintext ) { 00432 return $content; 00433 } 00434 $attribs = array( 'class' => 'history-deleted' ); 00435 return Html::rawElement( 'span', $attribs, $content ); 00436 } 00437 00444 protected function msg( $key ) { 00445 return wfMessage( $key ) 00446 ->inLanguage( $this->context->getLanguage() ) 00447 ->title( $this->context->getTitle() ); 00448 } 00449 00450 protected function makeUserLink( User $user ) { 00451 if ( $this->plaintext ) { 00452 $element = $user->getName(); 00453 } else { 00454 $element = Linker::userLink( 00455 $user->getId(), 00456 $user->getName() 00457 ); 00458 00459 if ( $this->linkFlood ) { 00460 $element .= Linker::userToolLinks( 00461 $user->getId(), 00462 $user->getName(), 00463 true, // Red if no edits 00464 0, // Flags 00465 $user->getEditCount() 00466 ); 00467 } 00468 } 00469 return $element; 00470 } 00471 00475 public function getPreloadTitles() { 00476 return array(); 00477 } 00478 00479 } 00480 00490 class LegacyLogFormatter extends LogFormatter { 00491 protected function getActionMessage() { 00492 $entry = $this->entry; 00493 $action = LogPage::actionText( 00494 $entry->getType(), 00495 $entry->getSubtype(), 00496 $entry->getTarget(), 00497 $this->plaintext ? null : $this->context->getSkin(), 00498 (array)$entry->getParameters(), 00499 !$this->plaintext // whether to filter [[]] links 00500 ); 00501 00502 $performer = $this->getPerformerElement(); 00503 return $performer . $this->msg( 'word-separator' )->text() . $action; 00504 } 00505 00506 } 00507 00512 class MoveLogFormatter extends LogFormatter { 00513 public function getPreloadTitles() { 00514 $params = $this->extractParameters(); 00515 return array( Title::newFromText( $params[3] ) ); 00516 } 00517 00518 protected function getMessageKey() { 00519 $key = parent::getMessageKey(); 00520 $params = $this->getMessageParameters(); 00521 if ( isset( $params[4] ) && $params[4] === '1' ) { 00522 $key .= '-noredirect'; 00523 } 00524 return $key; 00525 } 00526 00527 protected function getMessageParameters() { 00528 $params = parent::getMessageParameters(); 00529 $oldname = $this->makePageLink( $this->entry->getTarget(), array( 'redirect' => 'no' ) ); 00530 $newname = $this->makePageLink( Title::newFromText( $params[3] ) ); 00531 $params[2] = Message::rawParam( $oldname ); 00532 $params[3] = Message::rawParam( $newname ); 00533 return $params; 00534 } 00535 } 00536 00541 class DeleteLogFormatter extends LogFormatter { 00542 protected function getMessageKey() { 00543 $key = parent::getMessageKey(); 00544 if ( in_array( $this->entry->getSubtype(), array( 'event', 'revision' ) ) ) { 00545 if ( count( $this->getMessageParameters() ) < 5 ) { 00546 return "$key-legacy"; 00547 } 00548 } 00549 return $key; 00550 } 00551 00552 protected function getMessageParameters() { 00553 if ( isset( $this->parsedParametersDeleteLog ) ) { 00554 return $this->parsedParametersDeleteLog; 00555 } 00556 00557 $params = parent::getMessageParameters(); 00558 $subtype = $this->entry->getSubtype(); 00559 if ( in_array( $subtype, array( 'event', 'revision' ) ) ) { 00560 if ( 00561 ($subtype === 'event' && count( $params ) === 6 ) || 00562 ($subtype === 'revision' && isset( $params[3] ) && $params[3] === 'revision' ) 00563 ) { 00564 $paramStart = $subtype === 'revision' ? 4 : 3; 00565 00566 $old = $this->parseBitField( $params[$paramStart+1] ); 00567 $new = $this->parseBitField( $params[$paramStart+2] ); 00568 list( $hid, $unhid, $extra ) = RevisionDeleter::getChanges( $new, $old ); 00569 $changes = array(); 00570 foreach ( $hid as $v ) { 00571 $changes[] = $this->msg( "$v-hid" )->plain(); 00572 } 00573 foreach ( $unhid as $v ) { 00574 $changes[] = $this->msg( "$v-unhid" )->plain(); 00575 } 00576 foreach ( $extra as $v ) { 00577 $changes[] = $this->msg( $v )->plain(); 00578 } 00579 $changeText = $this->context->getLanguage()->listToText( $changes ); 00580 00581 00582 $newParams = array_slice( $params, 0, 3 ); 00583 $newParams[3] = $changeText; 00584 $count = count( explode( ',', $params[$paramStart] ) ); 00585 $newParams[4] = $this->context->getLanguage()->formatNum( $count ); 00586 return $this->parsedParametersDeleteLog = $newParams; 00587 } else { 00588 return $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 ); 00589 } 00590 } 00591 00592 return $this->parsedParametersDeleteLog = $params; 00593 } 00594 00595 protected function parseBitField( $string ) { 00596 // Input is like ofield=2134 or just the number 00597 if ( strpos( $string, 'field=' ) === 1 ) { 00598 list( , $field ) = explode( '=', $string ); 00599 return (int) $field; 00600 } else { 00601 return (int) $string; 00602 } 00603 } 00604 } 00605 00610 class PatrolLogFormatter extends LogFormatter { 00611 protected function getMessageKey() { 00612 $key = parent::getMessageKey(); 00613 $params = $this->getMessageParameters(); 00614 if ( isset( $params[5] ) && $params[5] ) { 00615 $key .= '-auto'; 00616 } 00617 return $key; 00618 } 00619 00620 protected function getMessageParameters() { 00621 $params = parent::getMessageParameters(); 00622 $newParams = array_slice( $params, 0, 3 ); 00623 00624 $target = $this->entry->getTarget(); 00625 $oldid = $params[3]; 00626 $revision = $this->context->getLanguage()->formatNum( $oldid, true ); 00627 00628 if ( $this->plaintext ) { 00629 $revlink = $revision; 00630 } elseif ( $target->exists() ) { 00631 $query = array( 00632 'oldid' => $oldid, 00633 'diff' => 'prev' 00634 ); 00635 $revlink = Linker::link( $target, htmlspecialchars( $revision ), array(), $query ); 00636 } else { 00637 $revlink = htmlspecialchars( $revision ); 00638 } 00639 00640 $newParams[3] = Message::rawParam( $revlink ); 00641 return $newParams; 00642 } 00643 } 00644 00649 class NewUsersLogFormatter extends LogFormatter { 00650 protected function getMessageParameters() { 00651 $params = parent::getMessageParameters(); 00652 if ( $this->entry->getSubtype() === 'create2' ) { 00653 if ( isset( $params[3] ) ) { 00654 $target = User::newFromId( $params[3] ); 00655 } else { 00656 $target = User::newFromName( $this->entry->getTarget()->getText(), false ); 00657 } 00658 $params[2] = Message::rawParam( $this->makeUserLink( $target ) ); 00659 $params[3] = $target->getName(); 00660 } 00661 return $params; 00662 } 00663 00664 public function getComment() { 00665 $timestamp = wfTimestamp( TS_MW, $this->entry->getTimestamp() ); 00666 if ( $timestamp < '20080129000000' ) { 00667 # Suppress $comment from old entries (before 2008-01-29), 00668 # not needed and can contain incorrect links 00669 return ''; 00670 } 00671 return parent::getComment(); 00672 } 00673 }