MediaWiki
REL1_22
|
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 // Message: log-show-hide-patrol 00176 $links[$type] = $this->msg( "log-show-hide-{$type}" )->rawParams( $link )->escaped(); 00177 $hiddens .= Html::hidden( "hide_{$type}_log", $val ) . "\n"; 00178 } 00179 // Build links 00180 return '<small>' . $this->getLanguage()->pipeList( $links ) . '</small>' . $hiddens; 00181 } 00182 00183 private function getDefaultQuery() { 00184 if ( !isset( $this->mDefaultQuery ) ) { 00185 $this->mDefaultQuery = $this->getRequest()->getQueryValues(); 00186 unset( $this->mDefaultQuery['title'] ); 00187 unset( $this->mDefaultQuery['dir'] ); 00188 unset( $this->mDefaultQuery['offset'] ); 00189 unset( $this->mDefaultQuery['limit'] ); 00190 unset( $this->mDefaultQuery['order'] ); 00191 unset( $this->mDefaultQuery['month'] ); 00192 unset( $this->mDefaultQuery['year'] ); 00193 } 00194 return $this->mDefaultQuery; 00195 } 00196 00201 private function getTypeMenu( $queryTypes ) { 00202 $queryType = count( $queryTypes ) == 1 ? $queryTypes[0] : ''; 00203 $selector = $this->getTypeSelector(); 00204 $selector->setDefault( $queryType ); 00205 return $selector->getHtml(); 00206 } 00207 00213 public function getTypeSelector() { 00214 $typesByName = array(); // Temporary array 00215 // First pass to load the log names 00216 foreach ( LogPage::validTypes() as $type ) { 00217 $page = new LogPage( $type ); 00218 $restriction = $page->getRestriction(); 00219 if ( $this->getUser()->isAllowed( $restriction ) ) { 00220 $typesByName[$type] = $page->getName()->text(); 00221 } 00222 } 00223 00224 // Second pass to sort by name 00225 asort( $typesByName ); 00226 00227 // Always put "All public logs" on top 00228 $public = $typesByName['']; 00229 unset( $typesByName[''] ); 00230 $typesByName = array( '' => $public ) + $typesByName; 00231 00232 $select = new XmlSelect( 'type' ); 00233 foreach ( $typesByName as $type => $name ) { 00234 $select->addOption( $name, $type ); 00235 } 00236 00237 return $select; 00238 } 00239 00244 private function getUserInput( $user ) { 00245 return '<span style="white-space: nowrap">' . 00246 Xml::inputLabel( $this->msg( 'specialloguserlabel' )->text(), 'user', 'mw-log-user', 15, $user ) . 00247 '</span>'; 00248 } 00249 00254 private function getTitleInput( $title ) { 00255 return '<span style="white-space: nowrap">' . 00256 Xml::inputLabel( $this->msg( 'speciallogtitlelabel' )->text(), 'page', 'mw-log-page', 20, $title ) . 00257 '</span>'; 00258 } 00259 00264 private function getTitlePattern( $pattern ) { 00265 return '<span style="white-space: nowrap">' . 00266 Xml::checkLabel( $this->msg( 'log-title-wildcard' )->text(), 'pattern', 'pattern', $pattern ) . 00267 '</span>'; 00268 } 00269 00274 private function getExtraInputs( $types ) { 00275 $offender = $this->getRequest()->getVal( 'offender' ); 00276 $user = User::newFromName( $offender, false ); 00277 if ( !$user || ( $user->getId() == 0 && !IP::isIPAddress( $offender ) ) ) { 00278 $offender = ''; // Blank field if invalid 00279 } 00280 if ( count( $types ) == 1 && $types[0] == 'suppress' ) { 00281 return Xml::inputLabel( $this->msg( 'revdelete-offender' )->text(), 'offender', 00282 'mw-log-offender', 20, $offender ); 00283 } 00284 return ''; 00285 } 00286 00290 public function beginLogEventsList() { 00291 return "<ul>\n"; 00292 } 00293 00297 public function endLogEventsList() { 00298 return "</ul>\n"; 00299 } 00300 00305 public function logLine( $row ) { 00306 $entry = DatabaseLogEntry::newFromRow( $row ); 00307 $formatter = LogFormatter::newFromEntry( $entry ); 00308 $formatter->setContext( $this->getContext() ); 00309 $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) ); 00310 00311 $time = htmlspecialchars( $this->getLanguage()->userTimeAndDate( 00312 $entry->getTimestamp(), $this->getUser() ) ); 00313 00314 $action = $formatter->getActionText(); 00315 00316 if ( $this->flags & self::NO_ACTION_LINK ) { 00317 $revert = ''; 00318 } else { 00319 $revert = $formatter->getActionLinks(); 00320 if ( $revert != '' ) { 00321 $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>'; 00322 } 00323 } 00324 00325 $comment = $formatter->getComment(); 00326 00327 // Some user can hide log items and have review links 00328 $del = $this->getShowHideLinks( $row ); 00329 00330 // Any tags... 00331 list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'logevent' ); 00332 $classes = array_merge( 00333 array( 'mw-logline-' . $entry->getType() ), 00334 $newClasses 00335 ); 00336 00337 return Html::rawElement( 'li', array( 'class' => $classes ), 00338 "$del $time $action $comment $revert $tagDisplay" ) . "\n"; 00339 } 00340 00345 private function getShowHideLinks( $row ) { 00346 if ( ( $this->flags == self::NO_ACTION_LINK ) // we don't want to see the links 00347 || $row->log_type == 'suppress' ) { // no one can hide items from the suppress log 00348 return ''; 00349 } 00350 $del = ''; 00351 $user = $this->getUser(); 00352 // Don't show useless checkbox to people who cannot hide log entries 00353 if ( $user->isAllowed( 'deletedhistory' ) ) { 00354 $canHide = $user->isAllowed( 'deletelogentry' ); 00355 if ( $row->log_deleted || $canHide ) { 00356 if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES ) { // Show checkboxes instead of links. 00357 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops 00358 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); 00359 } else { 00360 $del = Xml::check( 'showhiderevisions', false, array( 'name' => 'ids[' . $row->log_id . ']' ) ); 00361 } 00362 } else { 00363 if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops 00364 $del = Linker::revDeleteLinkDisabled( $canHide ); 00365 } else { 00366 $query = array( 00367 'target' => SpecialPage::getTitleFor( 'Log', $row->log_type )->getPrefixedDBkey(), 00368 'type' => 'logging', 00369 'ids' => $row->log_id, 00370 ); 00371 $del = Linker::revDeleteLink( $query, self::isDeleted( $row, LogPage::DELETED_RESTRICTED ), $canHide ); 00372 } 00373 } 00374 } 00375 } 00376 return $del; 00377 } 00378 00386 public static function typeAction( $row, $type, $action, $right = '' ) { 00387 $match = is_array( $type ) ? 00388 in_array( $row->log_type, $type ) : $row->log_type == $type; 00389 if ( $match ) { 00390 $match = is_array( $action ) ? 00391 in_array( $row->log_action, $action ) : $row->log_action == $action; 00392 if ( $match && $right ) { 00393 global $wgUser; 00394 $match = $wgUser->isAllowed( $right ); 00395 } 00396 } 00397 return $match; 00398 } 00399 00409 public static function userCan( $row, $field, User $user = null ) { 00410 return self::userCanBitfield( $row->log_deleted, $field, $user ); 00411 } 00412 00422 public static function userCanBitfield( $bitfield, $field, User $user = null ) { 00423 if ( $bitfield & $field ) { 00424 if ( $bitfield & LogPage::DELETED_RESTRICTED ) { 00425 $permission = 'suppressrevision'; 00426 } else { 00427 $permission = 'deletedhistory'; 00428 } 00429 wfDebug( "Checking for $permission due to $field match on $bitfield\n" ); 00430 if ( $user === null ) { 00431 global $wgUser; 00432 $user = $wgUser; 00433 } 00434 return $user->isAllowed( $permission ); 00435 } else { 00436 return true; 00437 } 00438 } 00439 00445 public static function isDeleted( $row, $field ) { 00446 return ( $row->log_deleted & $field ) == $field; 00447 } 00448 00471 public static function showLogExtract( 00472 &$out, $types = array(), $page = '', $user = '', $param = array() 00473 ) { 00474 $defaultParameters = array( 00475 'lim' => 25, 00476 'conds' => array(), 00477 'showIfEmpty' => true, 00478 'msgKey' => array( '' ), 00479 'wrap' => "$1", 00480 'flags' => 0, 00481 'useRequestParams' => false, 00482 ); 00483 # The + operator appends elements of remaining keys from the right 00484 # handed array to the left handed, whereas duplicated keys are NOT overwritten. 00485 $param += $defaultParameters; 00486 # Convert $param array to individual variables 00487 $lim = $param['lim']; 00488 $conds = $param['conds']; 00489 $showIfEmpty = $param['showIfEmpty']; 00490 $msgKey = $param['msgKey']; 00491 $wrap = $param['wrap']; 00492 $flags = $param['flags']; 00493 $useRequestParams = $param['useRequestParams']; 00494 if ( !is_array( $msgKey ) ) { 00495 $msgKey = array( $msgKey ); 00496 } 00497 00498 if ( $out instanceof OutputPage ) { 00499 $context = $out->getContext(); 00500 } else { 00501 $context = RequestContext::getMain(); 00502 } 00503 00504 # Insert list of top 50 (or top $lim) items 00505 $loglist = new LogEventsList( $context, null, $flags ); 00506 $pager = new LogPager( $loglist, $types, $user, $page, '', $conds ); 00507 if ( !$useRequestParams ) { 00508 # Reset vars that may have been taken from the request 00509 $pager->mLimit = 50; 00510 $pager->mDefaultLimit = 50; 00511 $pager->mOffset = ""; 00512 $pager->mIsBackwards = false; 00513 } 00514 if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset 00515 $pager->setOffset( $param['offset'] ); 00516 } 00517 if ( $lim > 0 ) { 00518 $pager->mLimit = $lim; 00519 } 00520 $logBody = $pager->getBody(); 00521 $s = ''; 00522 if ( $logBody ) { 00523 if ( $msgKey[0] ) { 00524 $s = '<div class="mw-warning-with-logexcerpt">'; 00525 00526 if ( count( $msgKey ) == 1 ) { 00527 $s .= $context->msg( $msgKey[0] )->parseAsBlock(); 00528 } else { // Process additional arguments 00529 $args = $msgKey; 00530 array_shift( $args ); 00531 $s .= $context->msg( $msgKey[0], $args )->parseAsBlock(); 00532 } 00533 } 00534 $s .= $loglist->beginLogEventsList() . 00535 $logBody . 00536 $loglist->endLogEventsList(); 00537 } elseif ( $showIfEmpty ) { 00538 $s = Html::rawElement( 'div', array( 'class' => 'mw-warning-logempty' ), 00539 $context->msg( 'logempty' )->parse() ); 00540 } 00541 if ( $pager->getNumRows() > $pager->mLimit ) { # Show "Full log" link 00542 $urlParam = array(); 00543 if ( $page instanceof Title ) { 00544 $urlParam['page'] = $page->getPrefixedDBkey(); 00545 } elseif ( $page != '' ) { 00546 $urlParam['page'] = $page; 00547 } 00548 if ( $user != '' ) { 00549 $urlParam['user'] = $user; 00550 } 00551 if ( !is_array( $types ) ) { # Make it an array, if it isn't 00552 $types = array( $types ); 00553 } 00554 # If there is exactly one log type, we can link to Special:Log?type=foo 00555 if ( count( $types ) == 1 ) { 00556 $urlParam['type'] = $types[0]; 00557 } 00558 $s .= Linker::link( 00559 SpecialPage::getTitleFor( 'Log' ), 00560 $context->msg( 'log-fulllog' )->escaped(), 00561 array(), 00562 $urlParam 00563 ); 00564 } 00565 if ( $logBody && $msgKey[0] ) { 00566 $s .= '</div>'; 00567 } 00568 00569 if ( $wrap != '' ) { // Wrap message in html 00570 $s = str_replace( '$1', $s, $wrap ); 00571 } 00572 00573 /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */ 00574 if ( wfRunHooks( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) { 00575 // $out can be either an OutputPage object or a String-by-reference 00576 if ( $out instanceof OutputPage ) { 00577 $out->addHTML( $s ); 00578 } else { 00579 $out = $s; 00580 } 00581 } 00582 00583 return $pager->getNumRows(); 00584 } 00585 00594 public static function getExcludeClause( $db, $audience = 'public', User $user = null ) { 00595 global $wgLogRestrictions; 00596 00597 if ( $audience != 'public' && $user === null ) { 00598 global $wgUser; 00599 $user = $wgUser; 00600 } 00601 00602 // Reset the array, clears extra "where" clauses when $par is used 00603 $hiddenLogs = array(); 00604 00605 // Don't show private logs to unprivileged users 00606 foreach ( $wgLogRestrictions as $logType => $right ) { 00607 if ( $audience == 'public' || !$user->isAllowed( $right ) ) { 00608 $hiddenLogs[] = $logType; 00609 } 00610 } 00611 if ( count( $hiddenLogs ) == 1 ) { 00612 return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] ); 00613 } elseif ( $hiddenLogs ) { 00614 return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')'; 00615 } 00616 return false; 00617 } 00618 }