X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/api/ApiFeedWatchlist.php diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php index 7b463856..e3a757f7 100644 --- a/includes/api/ApiFeedWatchlist.php +++ b/includes/api/ApiFeedWatchlist.php @@ -1,10 +1,10 @@ @gmail.com + * Copyright © 2006 Yuri Astrakhan "@gmail.com" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * This action allows users to get their watchlist items in RSS/Atom formats. * When executed, it performs a nested call to the API to get the needed data, @@ -38,59 +33,76 @@ if ( !defined( 'MEDIAWIKI' ) ) { */ class ApiFeedWatchlist extends ApiBase { - public function __construct( $main, $action ) { - parent::__construct( $main, $action ); - } + private $watchlistModule = null; + private $linkToSections = false; /** * This module uses a custom feed wrapper printer. + * + * @return ApiFormatFeedWrapper */ public function getCustomPrinter() { return new ApiFormatFeedWrapper( $this->getMain() ); } - private $linkToDiffs = false; - /** * Make a nested call to the API to request watchlist items in the last $hours. * Wrap the result as an RSS/Atom feed. */ public function execute() { - global $wgFeedClasses, $wgFeedLimit, $wgSitename, $wgLanguageCode; - + $config = $this->getConfig(); + $feedClasses = $config->get( 'FeedClasses' ); + $params = []; try { $params = $this->extractRequestParams(); + if ( !$config->get( 'Feed' ) ) { + $this->dieWithError( 'feed-unavailable' ); + } + + if ( !isset( $feedClasses[$params['feedformat']] ) ) { + $this->dieWithError( 'feed-invalid' ); + } + // limit to the number of hours going from now back $endTime = wfTimestamp( TS_MW, time() - intval( $params['hours'] * 60 * 60 ) ); // Prepare parameters for nested request - $fauxReqArr = array( + $fauxReqArr = [ 'action' => 'query', 'meta' => 'siteinfo', 'siprop' => 'general', 'list' => 'watchlist', - 'wlprop' => 'title|user|comment|timestamp', + 'wlprop' => 'title|user|comment|timestamp|ids', 'wldir' => 'older', // reverse order - from newest to oldest 'wlend' => $endTime, // stop at this time - 'wllimit' => ( 50 > $wgFeedLimit ) ? $wgFeedLimit : 50 - ); + 'wllimit' => min( 50, $this->getConfig()->get( 'FeedLimit' ) ) + ]; - if ( !is_null( $params['wlowner'] ) ) { + if ( $params['wlowner'] !== null ) { $fauxReqArr['wlowner'] = $params['wlowner']; } - if ( !is_null( $params['wltoken'] ) ) { + if ( $params['wltoken'] !== null ) { $fauxReqArr['wltoken'] = $params['wltoken']; } + if ( $params['wlexcludeuser'] !== null ) { + $fauxReqArr['wlexcludeuser'] = $params['wlexcludeuser']; + } + if ( $params['wlshow'] !== null ) { + $fauxReqArr['wlshow'] = $params['wlshow']; + } + if ( $params['wltype'] !== null ) { + $fauxReqArr['wltype'] = $params['wltype']; + } - // Support linking to diffs instead of article - if ( $params['linktodiffs'] ) { - $this->linkToDiffs = true; - $fauxReqArr['wlprop'] .= '|ids'; + // Support linking directly to sections when possible + // (possible only if section name is present in comment) + if ( $params['linktosections'] ) { + $this->linkToSections = true; } // Check for 'allrev' parameter, and if found, show all revisions to each page on wl. - if ( !is_null( $params['allrev'] ) ) { + if ( $params['allrev'] ) { $fauxReqArr['wlallrev'] = ''; } @@ -101,110 +113,200 @@ class ApiFeedWatchlist extends ApiBase { $module = new ApiMain( $fauxReq ); $module->execute(); - // Get data array - $data = $module->getResultData(); - - $feedItems = array(); - foreach ( (array)$data['query']['watchlist'] as $info ) { - $feedItems[] = $this->createFeedItem( $info ); + $data = $module->getResult()->getResultData( [ 'query', 'watchlist' ] ); + $feedItems = []; + foreach ( (array)$data as $key => $info ) { + if ( ApiResult::isMetadataKey( $key ) ) { + continue; + } + $feedItem = $this->createFeedItem( $info ); + if ( $feedItem ) { + $feedItems[] = $feedItem; + } } - $feedTitle = $wgSitename . ' - ' . wfMsgForContent( 'watchlist' ) . ' [' . $wgLanguageCode . ']'; + $msg = wfMessage( 'watchlist' )->inContentLanguage()->text(); + + $feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - ' . $msg . + ' [' . $this->getConfig()->get( 'LanguageCode' ) . ']'; $feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL(); - $feed = new $wgFeedClasses[$params['feedformat']] ( $feedTitle, htmlspecialchars( wfMsgForContent( 'watchlist' ) ), $feedUrl ); + $feed = new $feedClasses[$params['feedformat']] ( + $feedTitle, + htmlspecialchars( $msg ), + $feedUrl + ); ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems ); - } catch ( Exception $e ) { - // Error results should not be cached $this->getMain()->setCacheMaxAge( 0 ); - $feedTitle = $wgSitename . ' - Error - ' . wfMsgForContent( 'watchlist' ) . ' [' . $wgLanguageCode . ']'; + // @todo FIXME: Localise brackets + $feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - Error - ' . + wfMessage( 'watchlist' )->inContentLanguage()->text() . + ' [' . $this->getConfig()->get( 'LanguageCode' ) . ']'; $feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL(); $feedFormat = isset( $params['feedformat'] ) ? $params['feedformat'] : 'rss'; - $feed = new $wgFeedClasses[$feedFormat] ( $feedTitle, htmlspecialchars( wfMsgForContent( 'watchlist' ) ), $feedUrl ); - - if ( $e instanceof UsageException ) { - $errorCode = $e->getCodeString(); + $msg = wfMessage( 'watchlist' )->inContentLanguage()->escaped(); + $feed = new $feedClasses[$feedFormat] ( $feedTitle, $msg, $feedUrl ); + + if ( $e instanceof ApiUsageException ) { + foreach ( $e->getStatusValue()->getErrors() as $error ) { + $msg = ApiMessage::create( $error ) + ->inLanguage( $this->getLanguage() ); + $errorTitle = $this->msg( 'api-feed-error-title', $msg->getApiCode() ); + $errorText = $msg->text(); + $feedItems[] = new FeedItem( $errorTitle, $errorText, '', '', '' ); + } } else { - // Something is seriously wrong - $errorCode = 'internal_api_error'; + if ( $e instanceof UsageException ) { + $errorCode = $e->getCodeString(); + } else { + // Something is seriously wrong + $errorCode = 'internal_api_error'; + } + $errorTitle = $this->msg( 'api-feed-error-title', $errorCode ); + $errorText = $e->getMessage(); + $feedItems[] = new FeedItem( $errorTitle, $errorText, '', '', '' ); } - $errorText = $e->getMessage(); - $feedItems[] = new FeedItem( "Error ($errorCode)", $errorText, '', '', '' ); ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems ); } } + /** + * @param array $info + * @return FeedItem + */ private function createFeedItem( $info ) { + if ( !isset( $info['title'] ) ) { + // Probably a revdeled log entry, skip it. + return null; + } + $titleStr = $info['title']; $title = Title::newFromText( $titleStr ); - if ( $this->linkToDiffs && isset( $info['revid'] ) ) { - $titleUrl = $title->getFullURL( array( 'diff' => $info['revid'] ) ); + $curidParam = []; + if ( !$title || $title->isExternal() ) { + // Probably a formerly-valid title that's now conflicting with an + // interwiki prefix or the like. + if ( isset( $info['pageid'] ) ) { + $title = Title::newFromID( $info['pageid'] ); + $curidParam = [ 'curid' => $info['pageid'] ]; + } + if ( !$title || $title->isExternal() ) { + return null; + } + } + if ( isset( $info['revid'] ) ) { + $titleUrl = $title->getFullURL( [ 'diff' => $info['revid'] ] ); } else { - $titleUrl = $title->getFullURL(); + $titleUrl = $title->getFullURL( $curidParam ); } $comment = isset( $info['comment'] ) ? $info['comment'] : null; + + // Create an anchor to section. + // The anchor won't work for sections that have dupes on page + // as there's no way to strip that info from ApiWatchlist (apparently?). + // RegExp in the line below is equal to Linker::formatAutocomments(). + if ( $this->linkToSections && $comment !== null && + preg_match( '!(.*)/\*\s*(.*?)\s*\*/(.*)!', $comment, $matches ) + ) { + global $wgParser; + + $sectionTitle = $wgParser->stripSectionName( $matches[2] ); + $sectionTitle = Sanitizer::normalizeSectionNameWhitespace( $sectionTitle ); + $titleUrl .= Title::newFromText( '#' . $sectionTitle )->getFragmentForURL(); + } + $timestamp = $info['timestamp']; - $user = $info['user']; - $completeText = "$comment ($user)"; + if ( isset( $info['user'] ) ) { + $user = $info['user']; + $completeText = "$comment ($user)"; + } else { + $user = ''; + $completeText = (string)$comment; + } return new FeedItem( $titleStr, $completeText, $titleUrl, $timestamp, $user ); } - public function getAllowedParams() { - global $wgFeedClasses; - $feedFormatNames = array_keys( $wgFeedClasses ); - return array ( - 'feedformat' => array( + private function getWatchlistModule() { + if ( $this->watchlistModule === null ) { + $this->watchlistModule = $this->getMain()->getModuleManager()->getModule( 'query' ) + ->getModuleManager()->getModule( 'watchlist' ); + } + + return $this->watchlistModule; + } + + public function getAllowedParams( $flags = 0 ) { + $feedFormatNames = array_keys( $this->getConfig()->get( 'FeedClasses' ) ); + $ret = [ + 'feedformat' => [ ApiBase::PARAM_DFLT => 'rss', ApiBase::PARAM_TYPE => $feedFormatNames - ), - 'hours' => array( + ], + 'hours' => [ ApiBase::PARAM_DFLT => 24, ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_MIN => 1, ApiBase::PARAM_MAX => 72, - ), - 'allrev' => null, - 'wlowner' => array( - ApiBase::PARAM_TYPE => 'user' - ), - 'wltoken' => array( - ApiBase::PARAM_TYPE => 'string' - ), - 'linktodiffs' => false, - ); - } - - public function getParamDescription() { - return array( - 'feedformat' => 'The format of the feed', - 'hours' => 'List pages modified within this many hours from now', - 'allrev' => 'Include multiple revisions of the same page within given timeframe', - 'wlowner' => "The user whose watchlist you want (must be accompanied by {$this->getModulePrefix()}token if it's not you)", - 'wltoken' => 'Security token that requested user set in their preferences', - 'linktodiffs'=> 'Link to change differences instead of article pages' - ); - } + ], + 'linktosections' => false, + ]; + + $copyParams = [ + 'allrev' => 'allrev', + 'owner' => 'wlowner', + 'token' => 'wltoken', + 'show' => 'wlshow', + 'type' => 'wltype', + 'excludeuser' => 'wlexcludeuser', + ]; + if ( $flags ) { + $wlparams = $this->getWatchlistModule()->getAllowedParams( $flags ); + foreach ( $copyParams as $from => $to ) { + $p = $wlparams[$from]; + if ( !is_array( $p ) ) { + $p = [ ApiBase::PARAM_DFLT => $p ]; + } + if ( !isset( $p[ApiBase::PARAM_HELP_MSG] ) ) { + $p[ApiBase::PARAM_HELP_MSG] = "apihelp-query+watchlist-param-$from"; + } + if ( isset( $p[ApiBase::PARAM_TYPE] ) && is_array( $p[ApiBase::PARAM_TYPE] ) && + isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) + ) { + foreach ( $p[ApiBase::PARAM_TYPE] as $v ) { + if ( !isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] ) ) { + $p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] = "apihelp-query+watchlist-paramvalue-$from-$v"; + } + } + } + $ret[$to] = $p; + } + } else { + foreach ( $copyParams as $from => $to ) { + $ret[$to] = null; + } + } - public function getDescription() { - return 'This module returns a watchlist feed'; + return $ret; } - protected function getExamples() { - return array( - 'api.php?action=feedwatchlist', - 'api.php?action=feedwatchlist&allrev=allrev&linktodiffs=&hours=6' - ); + protected function getExamplesMessages() { + return [ + 'action=feedwatchlist' + => 'apihelp-feedwatchlist-example-default', + 'action=feedwatchlist&allrev=&hours=6' + => 'apihelp-feedwatchlist-example-all6hrs', + ]; } - public function getVersion() { - return __CLASS__ . ': $Id$'; + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist_feed'; } }