X-Git-Url: https://git.cyclocoop.org/admin/?a=blobdiff_plain;f=includes%2Fspecialpage%2FChangesListSpecialPage.php;h=dcd14e80981e8e23c6c94a78b690be548db9b5e4;hb=1aa0032c49d7dc9ba6ab12c2c7677d802dd9b09d;hp=98b7aa1925f071c77101bd76f8198ab8a6350cd3;hpb=a6a2d31b8f3290d31e400f77e459c9a8d4be94f3;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specialpage/ChangesListSpecialPage.php b/includes/specialpage/ChangesListSpecialPage.php index 98b7aa1925..dcd14e8098 100644 --- a/includes/specialpage/ChangesListSpecialPage.php +++ b/includes/specialpage/ChangesListSpecialPage.php @@ -32,6 +32,12 @@ use Wikimedia\Rdbms\IDatabase; * @ingroup SpecialPage */ abstract class ChangesListSpecialPage extends SpecialPage { + /** + * Preference name for saved queries. Subclasses that use saved queries should override this. + * @var string + */ + protected static $savedQueriesPreferenceName; + /** @var string */ protected $rcSubpage; @@ -78,6 +84,9 @@ abstract class ChangesListSpecialPage extends SpecialPage { public function __construct( $name, $restriction ) { parent::__construct( $name, $restriction ); + $nonRevisionTypes = [ RC_LOG ]; + Hooks::run( 'SpecialWatchlistGetNonRevisionTypes', [ &$nonRevisionTypes ] ); + $this->filterGroupDefinitions = [ [ 'name' => 'registration', @@ -316,8 +325,14 @@ abstract class ChangesListSpecialPage extends SpecialPage { 'description' => 'rcfilters-filter-lastrevision-description', 'default' => false, 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds, - &$query_options, &$join_conds ) { - $conds[] = 'rc_this_oldid <> page_latest'; + &$query_options, &$join_conds ) use ( $nonRevisionTypes ) { + $conds[] = $dbr->makeList( + [ + 'rc_this_oldid <> page_latest', + 'rc_type' => $nonRevisionTypes, + ], + LIST_OR + ); }, 'cssClassSuffix' => 'last', 'isRowApplicableCallable' => function ( $ctx, $rc ) { @@ -330,8 +345,14 @@ abstract class ChangesListSpecialPage extends SpecialPage { 'description' => 'rcfilters-filter-previousrevision-description', 'default' => false, 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds, - &$query_options, &$join_conds ) { - $conds[] = 'rc_this_oldid = page_latest'; + &$query_options, &$join_conds ) use ( $nonRevisionTypes ) { + $conds[] = $dbr->makeList( + [ + 'rc_this_oldid = page_latest', + 'rc_type' => $nonRevisionTypes, + ], + LIST_OR + ); }, 'cssClassSuffix' => 'previous', 'isRowApplicableCallable' => function ( $ctx, $rc ) { @@ -594,17 +615,11 @@ abstract class ChangesListSpecialPage extends SpecialPage { ) ); - $experimentalStructuredChangeFilters = - $this->getConfig()->get( 'StructuredChangeFiltersEnableExperimentalViews' ); - $out->addJsConfigVars( 'wgStructuredChangeFilters', $jsData['groups'] ); - $out->addJsConfigVars( - 'wgStructuredChangeFiltersEnableExperimentalViews', - $experimentalStructuredChangeFilters - ); + $out->addJsConfigVars( 'wgRCFiltersChangeTags', - $this->buildChangeTagList() + $this->getChangeTagList() ); $out->addJsConfigVars( 'StructuredChangeFiltersDisplayConfig', @@ -616,6 +631,26 @@ abstract class ChangesListSpecialPage extends SpecialPage { 'daysDefault' => $this->getDefaultDays(), ] ); + + $out->addJsConfigVars( + 'StructuredChangeFiltersLiveUpdatePollingRate', + $this->getConfig()->get( 'StructuredChangeFiltersLiveUpdatePollingRate' ) + ); + + if ( static::$savedQueriesPreferenceName ) { + $savedQueries = FormatJson::decode( + $this->getUser()->getOption( static::$savedQueriesPreferenceName ) + ); + if ( $savedQueries && isset( $savedQueries->default ) ) { + // If there is a default saved query, show a loading spinner, + // since the frontend is going to reload the results + $out->addBodyClasses( 'mw-rcfilters-ui-loading' ); + } + $out->addJsConfigVars( + 'wgStructuredChangeFiltersSavedQueriesPreferenceName', + static::$savedQueriesPreferenceName + ); + } } else { $out->addBodyClasses( 'mw-rcfilters-disabled' ); } @@ -626,49 +661,60 @@ abstract class ChangesListSpecialPage extends SpecialPage { * * @return Array Tag data */ - protected function buildChangeTagList() { - $explicitlyDefinedTags = array_fill_keys( ChangeTags::listExplicitlyDefinedTags(), 0 ); - $softwareActivatedTags = array_fill_keys( ChangeTags::listSoftwareActivatedTags(), 0 ); - - // Hit counts disabled for perf reasons, see T169997 - /* - $tagStats = ChangeTags::tagUsageStatistics(); - $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags, $tagStats ); - - // Sort by hits - arsort( $tagHitCounts ); - */ - $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags ); - - // Build the list and data - $result = []; - foreach ( $tagHitCounts as $tagName => $hits ) { - if ( - // Only get active tags - isset( $explicitlyDefinedTags[ $tagName ] ) || - isset( $softwareActivatedTags[ $tagName ] ) - ) { - // Parse description - $desc = ChangeTags::tagLongDescriptionMessage( $tagName, $this->getContext() ); - - $result[] = [ - 'name' => $tagName, - 'label' => Sanitizer::stripAllTags( - ChangeTags::tagDescription( $tagName, $this->getContext() ) - ), - 'description' => $desc ? Sanitizer::stripAllTags( $desc->parse() ) : '', - 'cssClass' => Sanitizer::escapeClass( 'mw-tag-' . $tagName ), - 'hits' => $hits, - ]; - } - } + protected function getChangeTagList() { + $cache = ObjectCache::getMainWANInstance(); + $context = $this->getContext(); + return $cache->getWithSetCallback( + $cache->makeKey( 'changeslistspecialpage-changetags', $context->getLanguage()->getCode() ), + $cache::TTL_MINUTE * 10, + function () use ( $context ) { + $explicitlyDefinedTags = array_fill_keys( ChangeTags::listExplicitlyDefinedTags(), 0 ); + $softwareActivatedTags = array_fill_keys( ChangeTags::listSoftwareActivatedTags(), 0 ); + + // Hit counts disabled for perf reasons, see T169997 + /* + $tagStats = ChangeTags::tagUsageStatistics(); + $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags, $tagStats ); + + // Sort by hits + arsort( $tagHitCounts ); + */ + $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags ); + + // Build the list and data + $result = []; + foreach ( $tagHitCounts as $tagName => $hits ) { + if ( + // Only get active tags + isset( $explicitlyDefinedTags[ $tagName ] ) || + isset( $softwareActivatedTags[ $tagName ] ) + ) { + // Parse description + $desc = ChangeTags::tagLongDescriptionMessage( $tagName, $context ); + + $result[] = [ + 'name' => $tagName, + 'label' => Sanitizer::stripAllTags( + ChangeTags::tagDescription( $tagName, $context ) + ), + 'description' => $desc ? Sanitizer::stripAllTags( $desc->parse() ) : '', + 'cssClass' => Sanitizer::escapeClass( 'mw-tag-' . $tagName ), + 'hits' => $hits, + ]; + } + } - // Instead of sorting by hit count (disabled, see above), sort by display name - usort( $result, function ( $a, $b ) { - return strcasecmp( $a['label'], $b['label'] ); - } ); + // Instead of sorting by hit count (disabled, see above), sort by display name + usort( $result, function ( $a, $b ) { + return strcasecmp( $a['label'], $b['label'] ); + } ); - return $result; + return $result; + }, + [ + 'lockTSE' => 30 + ] + ); } /** @@ -922,6 +968,11 @@ abstract class ChangesListSpecialPage extends SpecialPage { $opts->add( 'urlversion', 1 ); $opts->add( 'tagfilter', '' ); + $opts->add( 'days', $this->getDefaultDays(), FormOptions::FLOAT ); + $opts->add( 'limit', $this->getDefaultLimit(), FormOptions::INT ); + + $opts->add( 'from', '' ); + return $opts; } @@ -1075,6 +1126,9 @@ abstract class ChangesListSpecialPage extends SpecialPage { $query = wfArrayToCgi( $this->convertParamsForLink( $opts->getChangedValues() ) ); $this->getOutput()->redirect( $this->getPageTitle()->getCanonicalURL( $query ) ); } + + $opts->validateIntBounds( 'limit', 0, 5000 ); + $opts->validateBounds( 'days', 0, $this->getConfig()->get( 'RCMaxAge' ) / ( 3600 * 24 ) ); } /** @@ -1214,6 +1268,19 @@ abstract class ChangesListSpecialPage extends SpecialPage { } $conds[] = "rc_namespace $operator $value"; } + + // Calculate cutoff + $cutoff_unixtime = time() - $opts['days'] * 3600 * 24; + $cutoff = $dbr->timestamp( $cutoff_unixtime ); + + $fromValid = preg_match( '/^[0-9]{14}$/', $opts['from'] ); + if ( $fromValid && $opts['from'] > wfTimestamp( TS_MW, $cutoff ) ) { + $cutoff = $dbr->timestamp( $opts['from'] ); + } else { + $opts->reset( 'from' ); + } + + $conds[] = 'rc_timestamp >= ' . $dbr->addQuotes( $cutoff ); } /** @@ -1400,8 +1467,10 @@ abstract class ChangesListSpecialPage extends SpecialPage { $context->msg( 'recentchanges-legend-heading' )->parse(); # Collapsible + $collapsedState = $this->getRequest()->getCookie( 'changeslist-state' ); + $collapsedClass = $collapsedState === 'collapsed' ? ' mw-collapsed' : ''; $legend = - '
' . + '
' . $legendHeading . '
' . $legend . '
' . '
';