X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fspecialpage%2FChangesListSpecialPage.php;h=a3fee64d19bacc52a9b9e28f83891597f728991a;hb=63235f2d7f42f94337d1f12aaaab8322868732b9;hp=dcd14e80981e8e23c6c94a78b690be548db9b5e4;hpb=079d61fb79ac0a026c5a4c3b57bfbdaf3a037cd1;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specialpage/ChangesListSpecialPage.php b/includes/specialpage/ChangesListSpecialPage.php index dcd14e8098..a3fee64d19 100644 --- a/includes/specialpage/ChangesListSpecialPage.php +++ b/includes/specialpage/ChangesListSpecialPage.php @@ -21,6 +21,7 @@ * @ingroup SpecialPage */ use MediaWiki\Logger\LoggerFactory; +use Wikimedia\Rdbms\DBQueryTimeoutError; use Wikimedia\Rdbms\ResultWrapper; use Wikimedia\Rdbms\FakeResultWrapper; use Wikimedia\Rdbms\IDatabase; @@ -540,45 +541,59 @@ abstract class ChangesListSpecialPage extends SpecialPage { public function execute( $subpage ) { $this->rcSubpage = $subpage; - $rows = $this->getRows(); + $this->considerActionsForDefaultSavedQuery(); + $opts = $this->getOptions(); - if ( $rows === false ) { - $rows = new FakeResultWrapper( [] ); - } + try { + $rows = $this->getRows(); + if ( $rows === false ) { + $rows = new FakeResultWrapper( [] ); + } - // Used by Structured UI app to get results without MW chrome - if ( $this->getRequest()->getVal( 'action' ) === 'render' ) { - $this->getOutput()->setArticleBodyOnly( true ); - } + // Used by Structured UI app to get results without MW chrome + if ( $this->getRequest()->getVal( 'action' ) === 'render' ) { + $this->getOutput()->setArticleBodyOnly( true ); + } - // Used by "live update" and "view newest" to check - // if there's new changes with minimal data transfer - if ( $this->getRequest()->getBool( 'peek' ) ) { + // Used by "live update" and "view newest" to check + // if there's new changes with minimal data transfer + if ( $this->getRequest()->getBool( 'peek' ) ) { $code = $rows->numRows() > 0 ? 200 : 204; - $this->getOutput()->setStatusCode( $code ); - return; - } + $this->getOutput()->setStatusCode( $code ); + return; + } - $batch = new LinkBatch; - foreach ( $rows as $row ) { - $batch->add( NS_USER, $row->rc_user_text ); - $batch->add( NS_USER_TALK, $row->rc_user_text ); - $batch->add( $row->rc_namespace, $row->rc_title ); - if ( $row->rc_source === RecentChange::SRC_LOG ) { - $formatter = LogFormatter::newFromRow( $row ); - foreach ( $formatter->getPreloadTitles() as $title ) { - $batch->addObj( $title ); + $batch = new LinkBatch; + foreach ( $rows as $row ) { + $batch->add( NS_USER, $row->rc_user_text ); + $batch->add( NS_USER_TALK, $row->rc_user_text ); + $batch->add( $row->rc_namespace, $row->rc_title ); + if ( $row->rc_source === RecentChange::SRC_LOG ) { + $formatter = LogFormatter::newFromRow( $row ); + foreach ( $formatter->getPreloadTitles() as $title ) { + $batch->addObj( $title ); + } } } - } - $batch->execute(); + $batch->execute(); - $this->setHeaders(); - $this->outputHeader(); - $this->addModules(); - $this->webOutput( $rows, $opts ); + $this->setHeaders(); + $this->outputHeader(); + $this->addModules(); + $this->webOutput( $rows, $opts ); - $rows->free(); + $rows->free(); + } catch ( DBQueryTimeoutError $timeoutException ) { + MWExceptionHandler::logException( $timeoutException ); + + $this->setHeaders(); + $this->outputHeader(); + $this->addModules(); + + $this->getOutput()->setStatusCode( 500 ); + $this->webOutputHeader( 0, $opts ); + $this->outputTimeout(); + } if ( $this->getConfig()->get( 'EnableWANCacheReaper' ) ) { // Clean up any bad page entries for titles showing up in RC @@ -591,6 +606,77 @@ abstract class ChangesListSpecialPage extends SpecialPage { $this->includeRcFiltersApp(); } + /** + * Check whether or not the page should load defaults, and if so, whether + * a default saved query is relevant to be redirected to. If it is relevant, + * redirect properly with all necessary query parameters. + */ + protected function considerActionsForDefaultSavedQuery() { + if ( !$this->isStructuredFilterUiEnabled() ) { + return; + } + + $knownParams = call_user_func_array( + [ $this->getRequest(), 'getValues' ], + array_keys( $this->getOptions()->getAllValues() ) + ); + + // HACK: Temporarily until we can properly define "sticky" filters and parameters, + // we need to exclude several parameters we know should not be counted towards preventing + // the loading of defaults. + $excludedParams = [ 'limit' => '', 'days' => '', 'enhanced' => '', 'from' => '' ]; + $knownParams = array_diff_key( $knownParams, $excludedParams ); + + if ( + // If there are NO known parameters in the URL request + // (that are not excluded) then we need to check into loading + // the default saved query + count( $knownParams ) === 0 + ) { + // Get the saved queries data and parse it + $savedQueries = FormatJson::decode( + $this->getUser()->getOption( static::$savedQueriesPreferenceName ), + true + ); + + if ( $savedQueries && isset( $savedQueries[ 'default' ] ) ) { + // Only load queries that are 'version' 2, since those + // have parameter representation + if ( $savedQueries[ 'version' ] === '2' ) { + $savedQueryDefaultID = $savedQueries[ 'default' ]; + $defaultQuery = $savedQueries[ 'queries' ][ $savedQueryDefaultID ][ 'data' ]; + + // Build the entire parameter list + $query = array_merge( + $defaultQuery[ 'params' ], + $defaultQuery[ 'highlights' ], + [ + 'urlversion' => '2', + ] + ); + // Add to the query any parameters that we may have ignored before + // but are still valid and requested in the URL + $query = array_merge( $this->getRequest()->getValues(), $query ); + unset( $query[ 'title' ] ); + $this->getOutput()->redirect( $this->getPageTitle()->getCanonicalURL( $query ) ); + } else { + // There's a default, but the version is not 2, and the server can't + // actually recognize the query itself. This happens if it is before + // the conversion, so we need to tell the UI to reload saved query as + // it does the conversion to version 2 + $this->getOutput()->addJsConfigVars( + 'wgStructuredChangeFiltersDefaultSavedQueryExists', + true + ); + + // Add the class that tells the frontend it is still loading + // another query + $this->getOutput()->addBodyClasses( 'mw-rcfilters-ui-loading' ); + } + } + } + } + /** * Include the modules and configuration for the RCFilters app. * Conditional on the user having the feature enabled. @@ -632,25 +718,15 @@ abstract class ChangesListSpecialPage extends SpecialPage { ] ); + $out->addJsConfigVars( + 'wgStructuredChangeFiltersSavedQueriesPreferenceName', + static::$savedQueriesPreferenceName + ); + $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' ); } @@ -728,6 +804,17 @@ abstract class ChangesListSpecialPage extends SpecialPage { ); } + /** + * Add the "timeout" message to the output + */ + protected function outputTimeout() { + $this->getOutput()->addHTML( + '
' . + $this->msg( 'recentchanges-timeout' )->parse() . + '
' + ); + } + /** * Get the database result for this special page instance. Used by ApiFeedRecentChanges. * @@ -1346,16 +1433,26 @@ abstract class ChangesListSpecialPage extends SpecialPage { } /** - * Send output to the OutputPage object, only called if not used feeds + * Send header output to the OutputPage object, only called if not using feeds * - * @param ResultWrapper $rows Database rows + * @param int $rowCount Number of database rows * @param FormOptions $opts */ - public function webOutput( $rows, $opts ) { + private function webOutputHeader( $rowCount, $opts ) { if ( !$this->including() ) { $this->outputFeedLinks(); - $this->doHeader( $opts, $rows->numRows() ); + $this->doHeader( $opts, $rowCount ); } + } + + /** + * Send output to the OutputPage object, only called if not used feeds + * + * @param ResultWrapper $rows Database rows + * @param FormOptions $opts + */ + public function webOutput( $rows, $opts ) { + $this->webOutputHeader( $rows->numRows(), $opts ); $this->outputChangesList( $rows, $opts ); }