MediaWiki
REL1_21
|
00001 <?php 00026 class LogEventsList extends ContextSource { 00027 const NO_ACTION_LINK = 1; 00028 const NO_EXTRA_USER_LINKS = 2; 00029 const USE_REVDEL_CHECKBOXES = 4; 00030 00031 public $flags; 00032 00036 protected $mDefaultQuery; 00037 00048 public function __construct( $context, $unused = null, $flags = 0 ) { 00049 if ( $context instanceof IContextSource ) { 00050 $this->setContext( $context ); 00051 } else { 00052 // Old parameters, $context should be a Skin object 00053 $this->setContext( $context->getContext() ); 00054 } 00055 00056 $this->flags = $flags; 00057 } 00058 00065 public function getDisplayTitle() { 00066 return $this->getTitle(); 00067 } 00068 00074 public function showHeader( $type ) { 00075 wfDeprecated( __METHOD__, '1.19' ); 00076 // If only one log type is used, then show a special message... 00077 $headerType = (count( $type ) == 1) ? $type[0] : ''; 00078 $out = $this->getOutput(); 00079 if( LogPage::isLogType( $headerType ) ) { 00080 $page = new LogPage( $headerType ); 00081 $out->setPageTitle( $page->getName()->text() ); 00082 $out->addHTML( $page->getDescription()->parseAsBlock() ); 00083 } else { 00084 $out->addHTML( $this->msg( 'alllogstext' )->parse() ); 00085 } 00086 } 00087 00100 public function showOptions( $types=array(), $user = '', $page = '', $pattern = '', $year = '', 00101 $month = '', $filter = null, $tagFilter = '' ) { 00102 global $wgScript, $wgMiserMode; 00103 00104 $title = SpecialPage::getTitleFor( 'Log' ); 00105 00106 // For B/C, we take strings, but make sure they are converted... 00107 $types = ($types === '') ? array() : (array)$types; 00108 00109 $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter ); 00110 00111 $html = Html::hidden( 'title', $title->getPrefixedDBkey() ); 00112 00113 // Basic selectors 00114 $html .= $this->getTypeMenu( $types ) . "\n"; 00115 $html .= $this->getUserInput( $user ) . "\n"; 00116 $html .= $this->getTitleInput( $page ) . "\n"; 00117 $html .= $this->getExtraInputs( $types ) . "\n"; 00118 00119 // Title pattern, if allowed 00120 if ( !$wgMiserMode ) { 00121 $html .= $this->getTitlePattern( $pattern ) . "\n"; 00122 } 00123 00124 // date menu 00125 $html .= Xml::tags( 'p', null, Xml::dateMenu( $year, $month ) ); 00126 00127 // Tag filter 00128 if ( $tagSelector ) { 00129 $html .= Xml::tags( 'p', null, implode( ' ', $tagSelector ) ); 00130 } 00131 00132 // Filter links 00133 if ( $filter ) { 00134 $html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) ); 00135 } 00136 00137 // Submit button 00138 $html .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ); 00139 00140 // Fieldset 00141 $html = Xml::fieldset( $this->msg( 'log' )->text(), $html ); 00142 00143 // Form wrapping 00144 $html = Xml::tags( 'form', array( 'action' => $wgScript, 'method' => 'get' ), $html ); 00145 00146 $this->getOutput()->addHTML( $html ); 00147 } 00148 00153 private function getFilterLinks( $filter ) { 00154 // show/hide links 00155 $messages = array( $this->msg( 'show' )->escaped(), $this->msg( 'hide' )->escaped() ); 00156 // Option value -> message mapping 00157 $links = array(); 00158 $hiddens = ''; // keep track for "go" button 00159 foreach( $filter as $type => $val ) { 00160 // Should the below assignment be outside the foreach? 00161 // Then it would have to be copied. Not certain what is more expensive. 00162 $query = $this->getDefaultQuery(); 00163 $queryKey = "hide_{$type}_log"; 00164 00165 $hideVal = 1 - intval( $val ); 00166 $query[$queryKey] = $hideVal; 00167 00168 $link = Linker::linkKnown( 00169 $this->getTitle(), 00170 $messages[$hideVal], 00171 array(), 00172 $query 00173 ); 00174 00175 $links[$type] = $this->msg( "log-show-hide-{$type}" )->rawParams( $link )->escaped(); 00176 $hiddens .= Html::hidden( "hide_{$type}_log", $val ) . "\n"; 00177 } 00178 // Build links 00179 return '<small>' . $this->getLanguage()->pipeList( $links ) . '</small>' . $hiddens; 00180 } 00181 00182 private function getDefaultQuery() { 00183 if ( !isset( $this->mDefaultQuery ) ) { 00184 $this->mDefaultQuery = $this->getRequest()->getQueryValues(); 00185 unset( $this->mDefaultQuery['title'] ); 00186 unset( $this->mDefaultQuery['dir'] ); 00187 unset( $this->mDefaultQuery['offset'] ); 00188 unset( $this->mDefaultQuery['limit'] ); 00189 unset( $this->mDefaultQuery['order'] ); 00190 unset( $this->mDefaultQuery['month'] ); 00191 unset( $this->mDefaultQuery['year'] ); 00192 } 00193 return $this->mDefaultQuery; 00194 } 00195 00200 private function getTypeMenu( $queryTypes ) { 00201 $queryType = count( $queryTypes ) == 1 ? $queryTypes[0] : ''; 00202 $selector = $this->getTypeSelector(); 00203 $selector->setDefault( $queryType ); 00204 return $selector->getHtml(); 00205 } 00206 00212 public function getTypeSelector() { 00213 $typesByName = array(); // Temporary array 00214 // First pass to load the log names 00215 foreach( LogPage::validTypes() as $type ) { 00216 $page = new LogPage( $type ); 00217 $restriction = $page->getRestriction(); 00218 if ( $this->getUser()->isAllowed( $restriction ) ) { 00219 $typesByName[$type] = $page->getName()->text(); 00220 } 00221 } 00222 00223 // Second pass to sort by name 00224 asort( $typesByName ); 00225 00226 // Always put "All public logs" on top 00227 $public = $typesByName['']; 00228 unset( $typesByName[''] ); 00229 $typesByName = array( '' => $public ) + $typesByName; 00230 00231 $select = new XmlSelect( 'type' ); 00232 foreach( $typesByName as $type => $name ) { 00233 $select->addOption( $name, $type ); 00234 } 00235 00236 return $select; 00237 } 00238 00243 private function getUserInput( $user ) { 00244 return '<span style="white-space: nowrap">' . 00245 Xml::inputLabel( $this->msg( 'specialloguserlabel' )->text(), 'user', 'mw-log-user', 15, $user ) . 00246 '</span>'; 00247 } 00248 00253 private function getTitleInput( $title ) { 00254 return '<span style="white-space: nowrap">' . 00255 Xml::inputLabel( $this->msg( 'speciallogtitlelabel' )->text(), 'page', 'mw-log-page', 20, $title ) . 00256 '</span>'; 00257 } 00258 00263 private function getTitlePattern( $pattern ) { 00264 return '<span style="white-space: nowrap">' . 00265 Xml::checkLabel( $this->msg( 'log-title-wildcard' )->text(), 'pattern', 'pattern', $pattern ) . 00266 '</span>'; 00267 } 00268 00273 private function getExtraInputs( $types ) { 00274 $offender = $this->getRequest()->getVal( 'offender' ); 00275 $user = User::newFromName( $offender, false ); 00276 if( !$user || ( $user->getId() == 0 && !IP::isIPAddress( $offender ) ) ) { 00277 $offender = ''; // Blank field if invalid 00278 } 00279 if( count( $types ) == 1 && $types[0] == 'suppress' ) { 00280 return Xml::inputLabel( $this->msg( 'revdelete-offender' )->text(), 'offender', 00281 'mw-log-offender', 20, $offender ); 00282 } 00283 return ''; 00284 } 00285 00289 public function beginLogEventsList() { 00290 return "<ul>\n"; 00291 } 00292 00296 public function endLogEventsList() { 00297 return "</ul>\n"; 00298 } 00299 00304 public function logLine( $row ) { 00305 $entry = DatabaseLogEntry::newFromRow( $row ); 00306 $formatter = LogFormatter::newFromEntry( $entry ); 00307 $formatter->setContext( $this->getContext() ); 00308 $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) ); 00309 00310 $time = htmlspecialchars( $this->getLanguage()->userTimeAndDate( 00311 $entry->getTimestamp(), $this->getUser() ) ); 00312 00313 $action = $formatter->getActionText(); 00314 00315 if ( $this->flags & self::NO_ACTION_LINK ) { 00316 $revert = ''; 00317 } else { 00318 $revert = $formatter->getActionLinks(); 00319 if ( $revert != '' ) { 00320 $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>'; 00321 } 00322 } 00323 00324 $comment = $formatter->getComment(); 00325 00326 // Some user can hide log items and have review links 00327 $del = $this->getShowHideLinks( $row ); 00328 00329 // Any tags... 00330 list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'logevent' ); 00331 $classes = array_merge( 00332 array( 'mw-logline-' . $entry->getType() ), 00333 $newClasses 00334 ); 00335 00336 return Html::rawElement( 'li', array( 'class' => $classes ), 00337 "$del $time $action $comment $revert $tagDisplay" ) . "\n"; 00338 } 00339 00344 private function getShowHideLinks( $row ) { 00345 if( ( $this->flags == self::NO_ACTION_LINK ) // we don't want to see the links 00346 || $row->log_type == 'suppress' ) { // no one can hide items from the suppress log 00347 return ''; 00348 } 00349 $del = ''; 00350 $user = $this->getUser(); 00351 // Don't show useless checkbox to people who cannot hide log entries 00352 if( $user->isAllowed( 'deletedhistory' ) ) { 00353 $canHide = $user->isAllowed( 'deletelogentry' ); 00354 if( $row->log_deleted || $canHide ) { 00355 if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES ) { // Show checkboxes instead of links. 00356 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops 00357 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); 00358 } else { 00359 $del = Xml::check( 'showhiderevisions', false, array( 'name' => 'ids[' . $row->log_id . ']' ) ); 00360 } 00361 } else { 00362 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops 00363 $del = Linker::revDeleteLinkDisabled( $canHide ); 00364 } else { 00365 $query = array( 00366 'target' => SpecialPage::getTitleFor( 'Log', $row->log_type )->getPrefixedDBkey(), 00367 'type' => 'logging', 00368 'ids' => $row->log_id, 00369 ); 00370 $del = Linker::revDeleteLink( $query, self::isDeleted( $row, LogPage::DELETED_RESTRICTED ), $canHide ); 00371 } 00372 } 00373 } 00374 } 00375 return $del; 00376 } 00377 00385 public static function typeAction( $row, $type, $action, $right = '' ) { 00386 $match = is_array( $type ) ? 00387 in_array( $row->log_type, $type ) : $row->log_type == $type; 00388 if( $match ) { 00389 $match = is_array( $action ) ? 00390 in_array( $row->log_action, $action ) : $row->log_action == $action; 00391 if( $match && $right ) { 00392 global $wgUser; 00393 $match = $wgUser->isAllowed( $right ); 00394 } 00395 } 00396 return $match; 00397 } 00398 00408 public static function userCan( $row, $field, User $user = null ) { 00409 return self::userCanBitfield( $row->log_deleted, $field, $user ); 00410 } 00411 00421 public static function userCanBitfield( $bitfield, $field, User $user = null ) { 00422 if( $bitfield & $field ) { 00423 if ( $bitfield & LogPage::DELETED_RESTRICTED ) { 00424 $permission = 'suppressrevision'; 00425 } else { 00426 $permission = 'deletedhistory'; 00427 } 00428 wfDebug( "Checking for $permission due to $field match on $bitfield\n" ); 00429 if ( $user === null ) { 00430 global $wgUser; 00431 $user = $wgUser; 00432 } 00433 return $user->isAllowed( $permission ); 00434 } else { 00435 return true; 00436 } 00437 } 00438 00444 public static function isDeleted( $row, $field ) { 00445 return ( $row->log_deleted & $field ) == $field; 00446 } 00447 00469 public static function showLogExtract( 00470 &$out, $types=array(), $page = '', $user = '', $param = array() 00471 ) { 00472 $defaultParameters = array( 00473 'lim' => 25, 00474 'conds' => array(), 00475 'showIfEmpty' => true, 00476 'msgKey' => array( '' ), 00477 'wrap' => "$1", 00478 'flags' => 0 00479 ); 00480 # The + operator appends elements of remaining keys from the right 00481 # handed array to the left handed, whereas duplicated keys are NOT overwritten. 00482 $param += $defaultParameters; 00483 # Convert $param array to individual variables 00484 $lim = $param['lim']; 00485 $conds = $param['conds']; 00486 $showIfEmpty = $param['showIfEmpty']; 00487 $msgKey = $param['msgKey']; 00488 $wrap = $param['wrap']; 00489 $flags = $param['flags']; 00490 if ( !is_array( $msgKey ) ) { 00491 $msgKey = array( $msgKey ); 00492 } 00493 00494 if ( $out instanceof OutputPage ) { 00495 $context = $out->getContext(); 00496 } else { 00497 $context = RequestContext::getMain(); 00498 } 00499 00500 # Insert list of top 50 (or top $lim) items 00501 $loglist = new LogEventsList( $context, null, $flags ); 00502 $pager = new LogPager( $loglist, $types, $user, $page, '', $conds ); 00503 if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset 00504 $pager->setOffset( $param['offset'] ); 00505 } 00506 if( $lim > 0 ) $pager->mLimit = $lim; 00507 $logBody = $pager->getBody(); 00508 $s = ''; 00509 if( $logBody ) { 00510 if ( $msgKey[0] ) { 00511 $s = '<div class="mw-warning-with-logexcerpt">'; 00512 00513 if ( count( $msgKey ) == 1 ) { 00514 $s .= $context->msg( $msgKey[0] )->parseAsBlock(); 00515 } else { // Process additional arguments 00516 $args = $msgKey; 00517 array_shift( $args ); 00518 $s .= $context->msg( $msgKey[0], $args )->parseAsBlock(); 00519 } 00520 } 00521 $s .= $loglist->beginLogEventsList() . 00522 $logBody . 00523 $loglist->endLogEventsList(); 00524 } else { 00525 if ( $showIfEmpty ) { 00526 $s = Html::rawElement( 'div', array( 'class' => 'mw-warning-logempty' ), 00527 $context->msg( 'logempty' )->parse() ); 00528 } 00529 } 00530 if( $pager->getNumRows() > $pager->mLimit ) { # Show "Full log" link 00531 $urlParam = array(); 00532 if ( $page instanceof Title ) { 00533 $urlParam['page'] = $page->getPrefixedDBkey(); 00534 } elseif ( $page != '' ) { 00535 $urlParam['page'] = $page; 00536 } 00537 if ( $user != '' ) 00538 $urlParam['user'] = $user; 00539 if ( !is_array( $types ) ) # Make it an array, if it isn't 00540 $types = array( $types ); 00541 # If there is exactly one log type, we can link to Special:Log?type=foo 00542 if ( count( $types ) == 1 ) 00543 $urlParam['type'] = $types[0]; 00544 $s .= Linker::link( 00545 SpecialPage::getTitleFor( 'Log' ), 00546 $context->msg( 'log-fulllog' )->escaped(), 00547 array(), 00548 $urlParam 00549 ); 00550 } 00551 if ( $logBody && $msgKey[0] ) { 00552 $s .= '</div>'; 00553 } 00554 00555 if ( $wrap != '' ) { // Wrap message in html 00556 $s = str_replace( '$1', $s, $wrap ); 00557 } 00558 00559 /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */ 00560 if ( wfRunHooks( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) { 00561 // $out can be either an OutputPage object or a String-by-reference 00562 if ( $out instanceof OutputPage ) { 00563 $out->addHTML( $s ); 00564 } else { 00565 $out = $s; 00566 } 00567 } 00568 00569 return $pager->getNumRows(); 00570 } 00571 00580 public static function getExcludeClause( $db, $audience = 'public', User $user = null ) { 00581 global $wgLogRestrictions; 00582 00583 if ( $audience != 'public' && $user === null ) { 00584 global $wgUser; 00585 $user = $wgUser; 00586 } 00587 00588 // Reset the array, clears extra "where" clauses when $par is used 00589 $hiddenLogs = array(); 00590 00591 // Don't show private logs to unprivileged users 00592 foreach( $wgLogRestrictions as $logType => $right ) { 00593 if( $audience == 'public' || !$user->isAllowed( $right ) ) { 00594 $hiddenLogs[] = $logType; 00595 } 00596 } 00597 if( count( $hiddenLogs ) == 1 ) { 00598 return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] ); 00599 } elseif( $hiddenLogs ) { 00600 return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')'; 00601 } 00602 return false; 00603 } 00604 }